import com.google.auto.service.AutoService;
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.parser.*;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.Context;
//import modtools.annotations.all.TestAnn;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import java.util.Set;
import java.util.function.Predicate;

@AutoService({ Processor.class })
class TestProcessor extends AbstractProcessor {
	public void dealElement(Element element) {
		JCClassDecl classDecl = (JCClassDecl) trees.getTree(element);
		JCMethodDecl methodDecl = findChild(classDecl, Tag.METHODDEF, m -> m.name.toString().equals("m2"));
		methodDecl.body.stats = methodDecl.body.stats
				.append(parsers.newParser("Tools.aMethod(a -> {});", false, false, false).parseStatement());
	}

	public Set<String> getSupportedAnnotationTypes() {
		return Set.of(Test.class.getCanonicalName());
	}

	public Trees trees;
	public ParserFactory parsers;
	private boolean finished;

	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
		if (finished)
			return true;
		finished = true;
		for (TypeElement annotation : annotations) {
			for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
				dealElement(element);
			}
		}
		return true;
	}

	public synchronized void init(ProcessingEnvironment env) {
		super.init(env);

		Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
		trees = JavacTrees.instance(context);
		parsers = ParserFactory.instance(context);
	}

	public <T> T findChild(JCClassDecl parent, Tag tag, Predicate<T> predicate) {
		for (JCTree def : parent.defs) {
			if (def.getTag() == tag && predicate.test((T) def)) {
				return (T) def;
			}
		}
		return null;
	}

	public final SourceVersion getSupportedSourceVersion() {
		return SourceVersion.latestSupported();
	}
	
}


public class Test {
public static void aMethod(AInterface aInterface) {}
public static void m2() {};
public interface AInterface {
void get(Object o);
}
} 