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
38import java.io.File;
39import java.io.PrintWriter;
40import java.util.Arrays;
41import java.util.Set;
42
43import javax.annotation.processing.RoundEnvironment;
44import javax.lang.model.element.Element;
45import javax.lang.model.element.TypeElement;
46import javax.tools.JavaFileObject;
47import javax.tools.StandardJavaFileManager;
48import javax.tools.StandardLocation;
49
50import com.sun.source.doctree.DocCommentTree;
51import com.sun.source.tree.*;
52import com.sun.source.util.DocTrees;
53import com.sun.source.util.JavacTask;
54import com.sun.source.util.SourcePositions;
55import com.sun.source.util.TaskEvent;
56import com.sun.source.util.TaskListener;
57import com.sun.source.util.TreePath;
58import com.sun.source.util.TreePathScanner;
59import com.sun.tools.javac.api.JavacTool;
60import com.sun.tools.javac.tree.JCTree;
61import com.sun.tools.javac.tree.Pretty;
62import com.sun.tools.javac.util.Position;
63
64/** Doc comment: Test */
65public class Test {
66    public static final int EXPECT_DOC_COMMENTS = 3;
67
68    /** Doc comment: main */
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
81    Test(PrintWriter out) {
82        this.out = out;
83    }
84
85    /** Doc comment: 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
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
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
123    void error(String msg) {
124        out.println("Error: " + msg);
125        errors++;
126    }
127
128    class AnnoProc extends JavacTestingAbstractProcessor {
129        Checker checker;
130
131        AnnoProc(DocTrees trees) {
132            checker = new Checker(trees);
133        }
134
135        @Override
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
147        TaskListnr(DocTrees trees) {
148            checker = new Checker(trees);
149        }
150
151        public void started(TaskEvent e) {
152            if (e.getKind() == TaskEvent.Kind.ANALYZE)
153                checker.scan(new TreePath(e.getCompilationUnit()), null);
154        }
155
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
166        Checker(DocTrees trees) {
167            this.trees = trees;
168            srcPosns = trees.getSourcePositions();
169        }
170
171        @Override
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
191        public Void visitClass(ClassTree tree, Void ignore) {
192            checkComment();
193            return super.visitClass(tree, ignore);
194        }
195
196        @Override
197        public Void visitMethod(MethodTree tree, Void ignore) {
198            checkComment();
199            return super.visitMethod(tree, ignore);
200        }
201
202        @Override
203        public Void visitVariable(VariableTree tree, Void ignore) {
204            checkComment();
205            return super.visitVariable(tree, ignore);
206        }
207
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
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
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