Anonymous avatar Anonymous committed 1243282

FinalRule implemented as an AnnotationProcessor.

Comments (0)

Files changed (4)

analysis/src/j1/tutorial/javac/analysis/api/Utilities.java

 import java.util.Map.Entry;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
 
 public class Utilities {
 
     }
 
     public static AnnotationMirror findAppliedAnnotation(AnalysisContext context, Element forElement, String annotationFQN) {
+        return findAppliedAnnotation(forElement, annotationFQN);
+    }
+    
+    public static AnnotationMirror findAppliedAnnotation(ProcessingEnvironment context, Element forElement, String annotationFQN) {
+        return findAppliedAnnotation(forElement, annotationFQN);
+    }
+    
+    private static AnnotationMirror findAppliedAnnotation(Element forElement, String annotationFQN) {
         while (forElement != null) {
-            AnnotationMirror result = findAttachedAnnotation(context, forElement, annotationFQN);
+            AnnotationMirror result = findAttachedAnnotation(forElement, annotationFQN);
             
             if (result != null) return result;
             
     }
     
     public static AnnotationMirror findAttachedAnnotation(AnalysisContext context, Element forElement, String annotationFQN) {
+        return findAttachedAnnotation(forElement, annotationFQN);
+    }
+    
+    private static AnnotationMirror findAttachedAnnotation(Element forElement, String annotationFQN) {
         for (AnnotationMirror am : forElement.getAnnotationMirrors()) {
             if (((TypeElement) am.getAnnotationType().asElement()).getQualifiedName().contentEquals(annotationFQN)) {
                 return am;
         return null;
     }
     
+    public static <T> T getAttributeValue(ProcessingEnvironment context, AnnotationMirror annotation, String attribute, Class<T> clazz) {
+        return getAttributeValue(context.getElementUtils(), annotation, attribute, clazz);
+    }
+    
     public static <T> T getAttributeValue(AnalysisContext context, AnnotationMirror annotation, String attribute, Class<T> clazz) {
+        return getAttributeValue(context.getElementUtils(), annotation, attribute, clazz);
+    }
+    
+    private static <T> T getAttributeValue(Elements elements, AnnotationMirror annotation, String attribute, Class<T> clazz) {
         if (clazz.isArray()) {
-            Iterable<?> attributes = getAttributeValueInternal(context, annotation, attribute, Iterable.class);
+            Iterable<?> attributes = getAttributeValueInternal(elements, annotation, attribute, Iterable.class);
             Collection<Object> coll = new ArrayList<>();
 
             for (Object internal : attributes) {
 
             return clazz.cast(coll.toArray((Object[]) Array.newInstance(clazz.getComponentType(), 0)));
         } else {
-            return getAttributeValueInternal(context, annotation, attribute, clazz);
+            return getAttributeValueInternal(elements, annotation, attribute, clazz);
         }
     }
 
-    private static <T> T getAttributeValueInternal(AnalysisContext context, AnnotationMirror annotation, String attribute, Class<T> clazz) {
-        for (Entry<? extends ExecutableElement, ? extends AnnotationValue> e : context.getElementUtils().getElementValuesWithDefaults(annotation).entrySet()) {
+    private static <T> T getAttributeValueInternal(Elements elements, AnnotationMirror annotation, String attribute, Class<T> clazz) {
+        for (Entry<? extends ExecutableElement, ? extends AnnotationValue> e : elements.getElementValuesWithDefaults(annotation).entrySet()) {
             if (e.getKey().getSimpleName().contentEquals(attribute)) {
                 Object value = e.getValue().getValue();
 

analysis/src/j1/tutorial/javac/analysis/rules/FinalRule.java

 package j1.tutorial.javac.analysis.rules;
 
-import j1.tutorial.javac.analysis.api.AbstractTypeRule;
-import j1.tutorial.javac.analysis.api.AnalysisContext;
 import j1.tutorial.javac.analysis.api.Utilities;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
 import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.tools.Diagnostic.Kind;
+import org.openide.util.lookup.ServiceProvider;
 
-public class FinalRule extends AbstractTypeRule {
+@ServiceProvider(service=Processor.class)
+@SupportedAnnotationTypes("*")
+public class FinalRule extends AbstractProcessor {
 
     @Override
-    protected void analyseType(AnalysisContext ctx, TypeElement typeElement) {
-        for (TypeMirror superInterface : typeElement.getInterfaces()) {
-            if (superInterface.getKind() != TypeKind.DECLARED) continue;
-            TypeElement intf = (TypeElement) ((DeclaredType) superInterface).asElement();
-            AnnotationMirror friendAnnotation = Utilities.findAppliedAnnotation(ctx, intf, "j1.tutorial.javac.analysis.api.Final"); //TODO: string?
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        for (Element toProcess : roundEnv.getRootElements()) {
+            if (!toProcess.getKind().isClass() && !toProcess.getKind().isInterface()) {
+                continue;
+            }
+            TypeElement typeElement = (TypeElement) toProcess;
+            for (TypeMirror superInterface : typeElement.getInterfaces()) {
+                if (superInterface.getKind() != TypeKind.DECLARED) continue;
+                TypeElement intf = (TypeElement) ((DeclaredType) superInterface).asElement();
+                AnnotationMirror friendAnnotation = Utilities.findAppliedAnnotation(processingEnv, intf, "j1.tutorial.javac.analysis.api.Final"); //TODO: string?
 
-            if (friendAnnotation != null) {
-                boolean accepted = false;
+                if (friendAnnotation != null) {
+                    boolean accepted = false;
 
-                for (TypeMirror friend : Utilities.getAttributeValue(ctx, friendAnnotation, "implementors", TypeMirror[].class)) {
-                    if (typeElement.getQualifiedName().contentEquals(Utilities.toFQN(friend))) {
-                        accepted = true;
-                        break;
+                    for (TypeMirror friend : Utilities.getAttributeValue(processingEnv, friendAnnotation, "implementors", TypeMirror[].class)) {
+                        if (typeElement.getQualifiedName().contentEquals(Utilities.toFQN(friend))) {
+                            accepted = true;
+                            break;
+                        }
                     }
-                }
 
-                if (!accepted) {
-                    ctx.getMessager().printMessage(Kind.ERROR, "Cannot implement: " + intf.getQualifiedName().toString() + ", not its listed implementor", typeElement);
+                    if (!accepted) {
+                        processingEnv.getMessager().printMessage(Kind.ERROR, "Cannot implement: " + intf.getQualifiedName().toString() + ", not its listed implementor", typeElement);
+                    }
                 }
             }
         }
+        
+        return false;
     }
-    
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
 }

analysis/test/j1/tutorial/javac/analysis/api/RuleTest.java

 package j1.tutorial.javac.analysis.api;
 
 import com.sun.source.tree.CompilationUnitTree;
-import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.source.util.JavacTask;
 import java.io.File;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
+import javax.annotation.processing.Processor;
 import javax.tools.Diagnostic;
 import javax.tools.DiagnosticCollector;
 import javax.tools.JavaCompiler;
         return this;
     }
     
-    public RuleResult run(Class<? extends Rule> r) throws Exception {
+    public RuleResult run(final Class<? extends Rule> r) throws Exception {
+        return run(new AnalyzerImpl() {
+            @Override public void analyze(JavacTask javac, CompilationUnitTree cut) throws Exception {
+                r.newInstance().analyseFile(new AnalysisContext(javac), cut);
+            }
+        }, "-proc:none");
+    }
+    
+    public RuleResult runProcessor(final Class<? extends Processor> r) throws Exception {
+        File processorJar = new File(r.getProtectionDomain().getCodeSource().getLocation().toURI());
+        return run(null, "-processorpath", processorJar.getAbsolutePath(), "-processor", r.getName(), "-proc:only");
+    }
+    
+    private RuleResult run(AnalyzerImpl analyzer, String... extraOptions) throws Exception {
         final String bootPath = System.getProperty("sun.boot.class.path"); //NOI18N
         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
         assert tool != null;
         
         File apiJar = new File(Friend.class.getProtectionDomain().getCodeSource().getLocation().toURI());
         DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<>();
-        final JavacTaskImpl ct = (JavacTaskImpl)tool.getTask(null, null, dc, Arrays.asList("-bootclasspath",  bootPath, "-Xjcov", "-proc:none", "-classpath", apiJar.getAbsolutePath()), null, fos);
+        List<String> options = new ArrayList<>(Arrays.asList("-bootclasspath",  bootPath, "-Xjcov", "-classpath", apiJar.getAbsolutePath()));
+        options.addAll(Arrays.asList(extraOptions));
+        final JavacTask ct = (JavacTask) tool.getTask(null, null, dc, options, null, fos);
         Iterable<? extends CompilationUnitTree> cuts = ct.parse();
         
         ct.analyze();
         
-        for (CompilationUnitTree cut : cuts) {
-            r.newInstance().analyseFile(new AnalysisContext(ct), cut);
+        if (analyzer != null) {
+            for (CompilationUnitTree cut : cuts) {
+                analyzer.analyze(ct, cut);
+            }
         }
         
         List<String> warnings = new ArrayList<>();
             assertEquals(warnings, Arrays.asList(expectedWarnings), warnings.toString());
         }
     }
+
+    private static interface AnalyzerImpl {
+
+        public void analyze(JavacTask javac, CompilationUnitTree cut) throws Exception;
+        
+    }
 }

analysis/test/j1/tutorial/javac/analysis/rules/FinalRuleNGTest.java

                        "package test;\n" +
                        "import j1.tutorial.javac.analysis.api.Final;\n" +
                        "@Final(implementors={})\n" +
-                       "public class API {\n" +
+                       "public interface API {\n" +
                        "}\n")
-                .run(FinalRule.class)
+                .runProcessor(FinalRule.class)
                 .assertWarnings("/test/Test.java:14-50:Cannot implement: test.API, not its listed implementor");
     }
     
                        "package test;\n" +
                        "import j1.tutorial.javac.analysis.api.Final;\n" +
                        "@Final(implementors=Test.class)\n" +
-                       "public class API{\n" +
+                       "public interface API{\n" +
                        "}\n")
-                .run(FinalRule.class)
+                .runProcessor(FinalRule.class)
                 .assertWarnings();
     }
     
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.