1 /*
   2  * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 6346249 6392177 6411385
  27  * @summary new Trees API
  28  * @modules jdk.compiler/com.sun.tools.javac.tree
  29  */
  30 
  31 import java.io.*;
  32 import java.lang.annotation.*;
  33 import java.util.*;
  34 import javax.annotation.processing.*;
  35 import javax.lang.model.SourceVersion;
  36 import javax.lang.model.element.*;
  37 import javax.lang.model.type.*;
  38 import javax.tools.*;
  39 
  40 import com.sun.source.tree.*;
  41 import com.sun.source.util.*;
  42 import com.sun.tools.javac.tree.JCTree;
  43 import com.sun.tools.javac.tree.TreeInfo;
  44 
  45 @Anno
  46 @SupportedAnnotationTypes("*")
  47 public class TestTrees extends AbstractProcessor {
  48     @Anno
  49     void annoMethod() { }
  50 
  51     @Anno
  52     int annoField;
  53 
  54     @Anno
  55     public TestTrees() {
  56     }
  57 
  58     static final String testSrcDir = System.getProperty("test.src");
  59     static final String testClassDir = System.getProperty("test.classes");
  60     static final String self = TestTrees.class.getName();
  61     static PrintWriter out = new PrintWriter(System.err, true);
  62 
  63     public static void main(String[] args) throws IOException {
  64         new TestTrees().run();
  65     }
  66 
  67     void run() throws IOException {
  68 
  69         JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
  70 
  71         DiagnosticListener<JavaFileObject> dl = new DiagnosticListener<JavaFileObject>() {
  72                 public void report(Diagnostic d) {
  73                     error(d.toString());
  74                 }
  75             };
  76 
  77         try (StandardJavaFileManager fm = tool.getStandardFileManager(dl, null, null)) {
  78             Iterable<? extends JavaFileObject> files =
  79                 fm.getJavaFileObjectsFromFiles(Arrays.asList(new File(testSrcDir, self + ".java")));
  80 
  81             Iterable<String> opts = Arrays.asList(
  82                 "-XaddExports:"
  83                 + "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
  84                 "-d", ".",
  85                 "-XDcompilePolicy=simple");
  86 
  87             System.err.println("simple compilation, no processing");
  88             JavacTask task = (JavacTask) tool.getTask(out, fm, dl, opts, null, files);
  89             task.setTaskListener(new MyTaskListener(task));
  90             if (!task.call())
  91                 throw new AssertionError("compilation failed");
  92 
  93             opts =  Arrays.asList(
  94                 "-XaddExports:"
  95                 + "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
  96                 "-XDaccessInternalAPI",
  97                 "-d", ".",
  98                 "-processorpath", testClassDir,
  99                 "-processor", self,
 100                 "-XDcompilePolicy=simple");
 101 
 102             System.err.println();
 103             System.err.println("compilation with processing");
 104             task = (JavacTask) tool.getTask(out, fm, dl,opts, null, files);
 105             if (!task.call())
 106                 throw new AssertionError("compilation failed");
 107 
 108             if (errors > 0)
 109                 throw new AssertionError(errors + " errors occurred");
 110         }
 111     }
 112 
 113     void testElement(Trees trees, Element e) {
 114         trees.getClass();
 115         e.getClass();
 116 
 117         System.err.println("testElement: " + e);
 118         Tree tree = trees.getTree(e);
 119         //System.err.println(tree);
 120 
 121         if (TreeInfo.symbolFor((JCTree)tree) != e)
 122             error("bad result from getTree");
 123 
 124         TreePath path = trees.getPath(e);
 125         if (path == null) {
 126             error("getPath returned null");
 127             return;
 128         }
 129         if (path.getLeaf() != tree)
 130             error("bad result from getPath");
 131 
 132         Element e2 = trees.getElement(path);
 133         if (e2 == null) {
 134             error("getElement returned null");
 135             return;
 136         }
 137         if (e2 != e)
 138             error("bad result from getElement");
 139 
 140         // The TypeMirror is not available yet when annotation processing;
 141         // it is set up later during ANALYSE.
 142         TypeMirror t = trees.getTypeMirror(path);
 143         if (t != null && t.getKind() == TypeKind.DECLARED &&
 144                 ((DeclaredType)t).asElement() != e2)
 145             error("bad result from getTypeMirror");
 146 
 147         for (AnnotationMirror m: e.getAnnotationMirrors()) {
 148             testAnnotation(trees, e, m);
 149         }
 150     }
 151 
 152     void testAnnotation(Trees trees, Element e, AnnotationMirror a) {
 153         System.err.println("testAnnotation: " + e + " " + a);
 154         Tree tree = trees.getTree(e, a);
 155 
 156         if (tree.getKind() != Tree.Kind.ANNOTATION && tree.getKind() != Tree.Kind.TYPE_ANNOTATION)
 157             error("bad result from getTree");
 158 
 159         TreePath path = trees.getPath(e, a);
 160         if (path.getLeaf() != tree)
 161             error("bad result from getPath");
 162     }
 163 
 164     void testAllDeclarations(Trees trees, CompilationUnitTree cut) {
 165         new TreePathScanner<Void, Void>() {
 166             @Override public Void scan(Tree tree, Void p) {
 167                 if (tree == null) return null;
 168                 switch (tree.getKind()) {
 169                     case METHOD: case CLASS: case VARIABLE: case TYPE_PARAMETER:
 170                         TreePath path = new TreePath(getCurrentPath(), tree);
 171                         Element el = trees.getElement(path);
 172                         if (el == null) {
 173                             error("null element");
 174                         } else {
 175                             TreePath inferred = trees.getPath(el);
 176                             if (inferred == null) {
 177                                 error("null path");
 178                             } else {
 179                                 if (inferred.getLeaf() != path.getLeaf())
 180                                     error("bad result from getPath");
 181                             }
 182                             if (trees.getTree(el) != path.getLeaf())
 183                                 error("bad result from getTree");
 184                             for (AnnotationMirror m: el.getAnnotationMirrors()) {
 185                                 testAnnotation(trees, el, m);
 186                             }
 187                         }
 188                 }
 189                 return super.scan(tree, p);
 190             }
 191         }.scan(cut, null);
 192     }
 193 
 194     void error(String msg) {
 195         if (messager != null)
 196             // annotation processing will happen in a separate instance/classloader
 197             // so pass the message back to the calling instance.
 198             messager.printMessage(Diagnostic.Kind.ERROR, msg);
 199         else {
 200             System.err.println(msg);
 201             errors++;
 202         }
 203 
 204     }
 205 
 206     Messager messager;
 207     int errors;
 208 
 209 
 210     public boolean process(Set<? extends TypeElement> annos, RoundEnvironment rEnv) {
 211         Trees trees = Trees.instance(processingEnv);
 212         messager = processingEnv.getMessager();
 213 
 214         for (Element e: rEnv.getRootElements()) {
 215             testElement(trees, e);
 216         }
 217 
 218         for (TypeElement anno: annos) {
 219             Set<? extends Element> elts = rEnv.getElementsAnnotatedWith(anno);
 220             System.err.println("anno: " + anno);
 221             System.err.println("elts: " + elts);
 222             if (elts != null) { // 6397298, should return empty set
 223                 for (Element e: rEnv.getElementsAnnotatedWith(anno))
 224                     testElement(trees, e);
 225             }
 226         }
 227 
 228         return true;
 229     }
 230 
 231     @Override
 232     public SourceVersion getSupportedSourceVersion() {
 233         return SourceVersion.latest();
 234     }
 235 
 236     class MyTaskListener implements TaskListener {
 237         MyTaskListener(JavacTask task) {
 238             this.task = task;
 239         }
 240 
 241         public void started(TaskEvent e) {
 242             System.err.println("started " + e);
 243         }
 244 
 245         public void finished(TaskEvent e) {
 246             //System.err.println("finished " + e);
 247             switch (e.getKind()) {
 248             case ANALYZE:
 249                 testElement(Trees.instance(task), e.getTypeElement());
 250                 testAllDeclarations(Trees.instance(task), e.getCompilationUnit());
 251                 break;
 252             }
 253         }
 254 
 255         private final JavacTask task;
 256     }
 257 
 258     public static class TestTypeParams<@Anno T extends CharSequence> {
 259         public <@Anno T extends Object> TestTypeParams(T param) { }
 260         public <@Anno T extends Number> void m(T param) {
 261             int local;
 262             try {
 263                 new String();
 264             } catch (Exception exc) { }
 265         }
 266     }
 267 }
 268 
 269 @Retention(RetentionPolicy.SOURCE)
 270 @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE_PARAMETER,
 271          ElementType.FIELD, ElementType.LOCAL_VARIABLE})
 272 @interface Anno {
 273 }