1 /* 2 * Copyright (c) 2010, 2015, 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 8007344 27 * @summary javac may not make tree end positions and/or doc comments 28 * available to processors and listeners 29 * @library /tools/javac/lib 30 * @modules jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.file 32 * jdk.compiler/com.sun.tools.javac.tree 33 * jdk.compiler/com.sun.tools.javac.util 34 * @build JavacTestingAbstractProcessor 35 * @run main Test 36 */ 37 38 import java.io.File; 39 import java.io.PrintWriter; 40 import java.util.Arrays; 41 import java.util.Set; 42 43 import javax.annotation.processing.RoundEnvironment; 44 import javax.lang.model.element.Element; 45 import javax.lang.model.element.TypeElement; 46 import javax.tools.JavaFileObject; 47 import javax.tools.StandardJavaFileManager; 48 import javax.tools.StandardLocation; 49 50 import com.sun.source.doctree.DocCommentTree; 51 import com.sun.source.tree.*; 52 import com.sun.source.util.DocTrees; 53 import com.sun.source.util.JavacTask; 54 import com.sun.source.util.SourcePositions; 55 import com.sun.source.util.TaskEvent; 56 import com.sun.source.util.TaskListener; 57 import com.sun.source.util.TreePath; 58 import com.sun.source.util.TreePathScanner; 59 import com.sun.tools.javac.api.JavacTool; 60 import com.sun.tools.javac.tree.JCTree; 61 import com.sun.tools.javac.tree.Pretty; 62 import com.sun.tools.javac.util.Position; 63 64 /** Doc comment: Test */ 65 public class Test { 66 public static final int EXPECT_DOC_COMMENTS = 3; 67 68 /** Doc comment: main */ main(String... args)69 public static void main(String... args) throws Exception { 70 PrintWriter out = new PrintWriter(System.err); 71 try { 72 new Test(out).run(); 73 } finally { 74 out.flush(); 75 } 76 } 77 78 PrintWriter out; 79 int errors; 80 Test(PrintWriter out)81 Test(PrintWriter out) { 82 this.out = out; 83 } 84 85 /** Doc comment: run */ run()86 void run() throws Exception { 87 File testSrc = new File(System.getProperty("test.src")); 88 File thisFile = new File(testSrc, getClass().getName() + ".java"); 89 JavacTool javac = JavacTool.create(); 90 try (StandardJavaFileManager fm = javac.getStandardFileManager(null, null, null)) { 91 fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File("."))); 92 Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjects(thisFile); 93 testAnnoProcessor(javac, fm, fos, out, EXPECT_DOC_COMMENTS); 94 testTaskListener(javac, fm, fos, out, EXPECT_DOC_COMMENTS); 95 96 if (errors > 0) 97 throw new Exception(errors + " errors occurred"); 98 } 99 } 100 testAnnoProcessor(JavacTool javac, StandardJavaFileManager fm, Iterable<? extends JavaFileObject> files, PrintWriter out, int expectedDocComments)101 void testAnnoProcessor(JavacTool javac, StandardJavaFileManager fm, 102 Iterable<? extends JavaFileObject> files, PrintWriter out, 103 int expectedDocComments) { 104 out.println("Test annotation processor"); 105 JavacTask task = javac.getTask(out, fm, null, null, null, files); 106 AnnoProc ap = new AnnoProc(DocTrees.instance(task)); 107 task.setProcessors(Arrays.asList(ap)); 108 task.call(); 109 ap.checker.checkDocComments(expectedDocComments); 110 } 111 testTaskListener(JavacTool javac, StandardJavaFileManager fm, Iterable<? extends JavaFileObject> files, PrintWriter out, int expectedDocComments)112 void testTaskListener(JavacTool javac, StandardJavaFileManager fm, 113 Iterable<? extends JavaFileObject> files, PrintWriter out, 114 int expectedDocComments) { 115 out.println("Test task listener"); 116 JavacTask task = javac.getTask(out, fm, null, null, null, files); 117 TaskListnr tl = new TaskListnr(DocTrees.instance(task)); 118 task.addTaskListener(tl); 119 task.call(); 120 tl.checker.checkDocComments(expectedDocComments); 121 } 122 error(String msg)123 void error(String msg) { 124 out.println("Error: " + msg); 125 errors++; 126 } 127 128 class AnnoProc extends JavacTestingAbstractProcessor { 129 Checker checker; 130 AnnoProc(DocTrees trees)131 AnnoProc(DocTrees trees) { 132 checker = new Checker(trees); 133 } 134 135 @Override process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)136 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 137 for (Element e : roundEnv.getRootElements()) { 138 checker.scan(checker.trees.getPath(e), null); 139 } 140 return true; 141 } 142 } 143 144 class TaskListnr implements TaskListener { 145 Checker checker; 146 TaskListnr(DocTrees trees)147 TaskListnr(DocTrees trees) { 148 checker = new Checker(trees); 149 } 150 started(TaskEvent e)151 public void started(TaskEvent e) { 152 if (e.getKind() == TaskEvent.Kind.ANALYZE) 153 checker.scan(new TreePath(e.getCompilationUnit()), null); 154 } 155 finished(TaskEvent e)156 public void finished(TaskEvent e) { 157 } 158 } 159 160 class Checker extends TreePathScanner<Void,Void> { 161 DocTrees trees; 162 SourcePositions srcPosns; 163 164 int docComments = 0; 165 Checker(DocTrees trees)166 Checker(DocTrees trees) { 167 this.trees = trees; 168 srcPosns = trees.getSourcePositions(); 169 } 170 171 @Override scan(Tree tree, Void ignore)172 public Void scan(Tree tree, Void ignore) { 173 if (tree != null) { 174 switch (tree.getKind()) { 175 // HACK: Workaround 8007350 176 // Some tree nodes do not have endpos set 177 case ASSIGNMENT: 178 case BLOCK: 179 case IDENTIFIER: 180 case METHOD_INVOCATION: 181 break; 182 183 default: 184 checkEndPos(getCurrentPath().getCompilationUnit(), tree); 185 } 186 } 187 return super.scan(tree, ignore); 188 } 189 190 @Override visitClass(ClassTree tree, Void ignore)191 public Void visitClass(ClassTree tree, Void ignore) { 192 checkComment(); 193 return super.visitClass(tree, ignore); 194 } 195 196 @Override visitMethod(MethodTree tree, Void ignore)197 public Void visitMethod(MethodTree tree, Void ignore) { 198 checkComment(); 199 return super.visitMethod(tree, ignore); 200 } 201 202 @Override visitVariable(VariableTree tree, Void ignore)203 public Void visitVariable(VariableTree tree, Void ignore) { 204 checkComment(); 205 return super.visitVariable(tree, ignore); 206 } 207 checkComment()208 void checkComment() { 209 DocCommentTree dc = trees.getDocCommentTree(getCurrentPath()); 210 if (dc != null) { 211 out.println("comment: " + dc.toString().replaceAll("\\s+", " ")); 212 docComments++; 213 } 214 } 215 checkEndPos(CompilationUnitTree unit, Tree tree)216 void checkEndPos(CompilationUnitTree unit, Tree tree) { 217 long sp = srcPosns.getStartPosition(unit, tree); 218 long ep = srcPosns.getEndPosition(unit, tree); 219 if (sp >= 0 && ep == Position.NOPOS) { 220 error("endpos not set for " + tree.getKind() 221 + " " + Pretty.toSimpleString(((JCTree) tree)) 222 +", start:" + sp); 223 } 224 } 225 checkDocComments(int expected)226 void checkDocComments(int expected) { 227 if (docComments != expected) { 228 error("Unexpected number of doc comments received: " 229 + docComments + ", expected: " + expected); 230 } 231 } 232 233 } 234 } 235