1 /*
2  * Copyright (c) 2013, 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 8012929
27  * @summary Trees.getElement should work not only for declaration trees, but also for use-trees
28  * @modules jdk.compiler
29  * @build TestGetElementReference
30  * @run main TestGetElementReference
31  */
32 
33 import com.sun.source.tree.CompilationUnitTree;
34 import com.sun.source.tree.Tree;
35 import com.sun.source.util.*;
36 import java.io.File;
37 import java.io.IOException;
38 import java.net.URI;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42 import java.util.regex.Matcher;
43 import java.util.regex.Pattern;
44 import javax.lang.model.element.Element;
45 import javax.tools.Diagnostic;
46 import javax.tools.DiagnosticCollector;
47 import javax.tools.JavaFileObject;
48 import javax.tools.SimpleJavaFileObject;
49 import javax.tools.StandardJavaFileManager;
50 import javax.tools.ToolProvider;
51 
52 public class TestGetElementReference {
53 
main(String... args)54     public static void main(String... args) throws IOException {
55         analyze("TestGetElementReferenceData.java");
56         analyze("mod/module-info.java", "mod/api/pkg/Api.java");
57     }
58 
analyze(String... fileNames)59     private static void analyze(String... fileNames) throws IOException {
60         try (StandardJavaFileManager fm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null)) {
61             List<JavaFileObject> files = new ArrayList<>();
62             for (String fileName : fileNames) {
63                 File source = new File(System.getProperty("test.src", "."), fileName.replace('/', File.separatorChar)).getAbsoluteFile();
64                 for (JavaFileObject f : fm.getJavaFileObjects(source)) {
65                     files.add(f);
66                 }
67             }
68             DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
69             JavacTask ct = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, diagnostics, Arrays.asList("-Xjcov"), null, files);
70             Trees trees = Trees.instance(ct);
71             CompilationUnitTree cut = ct.parse().iterator().next();
72 
73             ct.analyze();
74 
75             for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) {
76                 if (d.getKind() == Diagnostic.Kind.ERROR) {
77                     throw new IllegalStateException("Should have been attributed without errors: " + diagnostics.getDiagnostics());
78                 }
79             }
80 
81             Pattern p = Pattern.compile("/\\*getElement:(.*?)\\*/");
82             Matcher m = p.matcher(cut.getSourceFile().getCharContent(false));
83 
84             while (m.find()) {
85                 TreePath tp = pathFor(trees, cut, m.start() - 1);
86                 String expected = m.group(1);
87                 if (expected.startsWith("getParentPath:")) {
88                     tp = tp.getParentPath();
89                     expected = expected.substring("getParentPath:".length());
90                 }
91                 Element found = trees.getElement(tp);
92                 String actual = found != null ? found.getKind() + ":" + symbolToString(found) : "<null>";
93 
94                 if (!expected.equals(actual)) {
95                     throw new IllegalStateException("expected=" + expected + "; actual=" + actual + "; tree: " + tp.getLeaf());
96                 }
97             }
98         }
99     }
100 
pathFor(final Trees trees, final CompilationUnitTree cut, final int pos)101     private static TreePath pathFor(final Trees trees, final CompilationUnitTree cut, final int pos) {
102         final TreePath[] result = new TreePath[1];
103 
104         new TreePathScanner<Void, Void>() {
105             @Override public Void scan(Tree node, Void p) {
106                 if (   node != null
107                     && trees.getSourcePositions().getStartPosition(cut, node) <= pos
108                     && pos <= trees.getSourcePositions().getEndPosition(cut, node)) {
109                     result[0] = new TreePath(getCurrentPath(), node);
110                     return super.scan(node, p);
111                 }
112                 return null;
113             }
114         }.scan(cut, null);
115 
116         return result[0];
117     }
118 
symbolToString(Element el)119     private static String symbolToString(Element el) {
120         switch (el.getKind()) {
121             case METHOD: return symbolToString(el.getEnclosingElement()) + "." + el.toString();
122             case CONSTRUCTOR: return symbolToString(el.getEnclosingElement().getEnclosingElement()) + "." + el.toString();
123             default:
124                 return el.toString();
125         }
126     }
127 
128     static class TestFileObject extends SimpleJavaFileObject {
129         private final String text;
TestFileObject(String text)130         public TestFileObject(String text) {
131             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
132             this.text = text;
133         }
getCharContent(boolean ignoreEncodingErrors)134         @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) {
135             return text;
136         }
137     }
138 
139 }
140