Java8, how discover the class and method name in visitMethodInvocation?

后端 未结 2 1574
予麋鹿
予麋鹿 2020-12-15 14:30

With Java7 and Java8, I would like to generate a warning if some methods was called. The warning will be print if a specific jar is present when then user compile.

I

2条回答
  •  爱一瞬间的悲伤
    2020-12-15 15:17

    You can do something like:

    package mystuff;
    
    import com.sun.source.tree.*;
    import com.sun.source.util.*;
    import java.util.*;
    import javax.annotation.processing.*;
    import javax.lang.model.element.*;
    import javax.tools.*;
    
    @SupportedAnnotationTypes("*")
        public class Proc extends AbstractProcessor{
        @Override
            public boolean process(Setannotations,RoundEnvironment roundEnvironment){
            final Trees trees=Trees.instance(processingEnv);
            for(Element element:roundEnvironment.getRootElements()){
            TreePath path=trees.getPath(element);
            final CompilationUnitTree compilationUnit=path.getCompilationUnit();
            compilationUnit.accept(new TreeScanner(){
                @Override
                    public Object visitMethodInvocation(MethodInvocationTree tree,Object data){
                    tree.getMethodSelect().accept(new SimpleTreeVisitor(){
                        @Override
                        public Object visitMemberSelect(MemberSelectTree tree,Object data){
                        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,String.format("class:  %1$s\nmethod: %2$s",tree.getExpression(),tree.getIdentifier()));
                        return null;
                        }
                    },null);
                    return null;
                }
                },null);
            }
            return true;
        }
        }
    

    I used that processor to process the below class

    package stuff;
    
    import java.util.*;
    
    @MyAnnotation
    class MyProgram{
        public void run(){
        System.out.println("Hello World!");
        }
    }
    

    and achieved this result:

    class:  System.out
      method: println
    

    I am pretty sure that the method name generated is what you are looking for. I am pretty sure that the "class" is not exactly what you are looking for, but is a pretty good start.

    In my example you probably wanted it to print "java.io.PrintStream" for the class. To get that you could use processingEnv.getElementUtils().getTypeElement("java.lang.System") to get a TypeElement representing the system class. Then you can use processingEnv.getElementUtils().getAllMembers() to get every single member of the system class. Iterate through that to find out. Use the asType method to get its type.

    The preceding paragraph was a gross simplification. The processor did not know a priori that out is a static member of a class that is part of the implicitly imported java.lang package. So your code will have to try and fail to find the following classes System and java.util.System (because it is in the imports), System.out, java.util.System.out, and java.lang.System.out.

    I only dealt with MemberSelect. You will have to deal with other possibilities including MethodInvocation. For example new Object().toString().hashCode() should be class=Object, method=hashCode.

提交回复
热议问题