|
1 /* |
|
2 * Copyright (c) 2014, 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. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package jdk.jshell; |
|
27 |
|
28 |
|
29 import com.sun.source.tree.ClassTree; |
|
30 import com.sun.source.tree.CompilationUnitTree; |
|
31 import com.sun.source.tree.ExpressionTree; |
|
32 import com.sun.source.tree.MethodTree; |
|
33 import com.sun.source.tree.ReturnTree; |
|
34 import com.sun.source.tree.StatementTree; |
|
35 import com.sun.source.tree.Tree; |
|
36 import com.sun.source.tree.VariableTree; |
|
37 import com.sun.source.util.SourcePositions; |
|
38 import com.sun.source.util.TreePath; |
|
39 import com.sun.source.util.Trees; |
|
40 import com.sun.tools.javac.code.Type; |
|
41 import com.sun.tools.javac.code.Type.MethodType; |
|
42 import com.sun.tools.javac.code.Types; |
|
43 import com.sun.tools.javac.tree.JCTree.JCMethodDecl; |
|
44 import com.sun.tools.javac.util.JavacMessages; |
|
45 import com.sun.tools.javac.util.Name; |
|
46 import static jdk.jshell.Util.isDoIt; |
|
47 import jdk.jshell.Wrap.Range; |
|
48 import java.util.List; |
|
49 import java.util.Locale; |
|
50 import java.util.function.BinaryOperator; |
|
51 import javax.lang.model.type.TypeMirror; |
|
52 |
|
53 /** |
|
54 * Utilities for analyzing compiler API parse trees. |
|
55 * @author Robert Field |
|
56 */ |
|
57 |
|
58 class TreeDissector { |
|
59 |
|
60 private static final String OBJECT_TYPE = "Object"; |
|
61 |
|
62 static class ExpressionInfo { |
|
63 |
|
64 boolean isNonVoid; |
|
65 String typeName; |
|
66 ExpressionTree tree; |
|
67 String signature; |
|
68 } |
|
69 |
|
70 private final TaskFactory.BaseTask bt; |
|
71 private ClassTree firstClass; |
|
72 private SourcePositions theSourcePositions = null; |
|
73 |
|
74 TreeDissector(TaskFactory.BaseTask bt) { |
|
75 this.bt = bt; |
|
76 } |
|
77 |
|
78 |
|
79 ClassTree firstClass() { |
|
80 if (firstClass == null) { |
|
81 firstClass = computeFirstClass(); |
|
82 } |
|
83 return firstClass; |
|
84 } |
|
85 |
|
86 CompilationUnitTree cuTree() { |
|
87 return bt.cuTree(); |
|
88 } |
|
89 |
|
90 Types types() { |
|
91 return bt.types(); |
|
92 } |
|
93 |
|
94 Trees trees() { |
|
95 return bt.trees(); |
|
96 } |
|
97 |
|
98 SourcePositions getSourcePositions() { |
|
99 if (theSourcePositions == null) { |
|
100 theSourcePositions = trees().getSourcePositions(); |
|
101 } |
|
102 return theSourcePositions; |
|
103 } |
|
104 |
|
105 int getStartPosition(Tree tree) { |
|
106 return (int) getSourcePositions().getStartPosition(cuTree(), tree); |
|
107 } |
|
108 |
|
109 int getEndPosition(Tree tree) { |
|
110 return (int) getSourcePositions().getEndPosition(cuTree(), tree); |
|
111 } |
|
112 |
|
113 Range treeToRange(Tree tree) { |
|
114 return new Range(getStartPosition(tree), getEndPosition(tree)); |
|
115 } |
|
116 |
|
117 Range treeListToRange(List<? extends Tree> treeList) { |
|
118 int start = Integer.MAX_VALUE; |
|
119 int end = -1; |
|
120 for (Tree t : treeList) { |
|
121 int tstart = getStartPosition(t); |
|
122 int tend = getEndPosition(t); |
|
123 if (tstart < start) { |
|
124 start = tstart; |
|
125 } |
|
126 if (tend > end) { |
|
127 end = tend; |
|
128 } |
|
129 } |
|
130 if (start == Integer.MAX_VALUE) { |
|
131 return null; |
|
132 } |
|
133 return new Range(start, end); |
|
134 } |
|
135 |
|
136 Tree firstClassMember() { |
|
137 if (firstClass() != null) { |
|
138 //TODO: missing classes |
|
139 for (Tree mem : firstClass().getMembers()) { |
|
140 if (mem.getKind() == Tree.Kind.VARIABLE) { |
|
141 return mem; |
|
142 } |
|
143 if (mem.getKind() == Tree.Kind.METHOD) { |
|
144 MethodTree mt = (MethodTree) mem; |
|
145 if (!isDoIt(mt.getName()) && !mt.getName().toString().equals("<init>")) { |
|
146 return mt; |
|
147 } |
|
148 } |
|
149 } |
|
150 } |
|
151 return null; |
|
152 } |
|
153 |
|
154 StatementTree firstStatement() { |
|
155 if (firstClass() != null) { |
|
156 for (Tree mem : firstClass().getMembers()) { |
|
157 if (mem.getKind() == Tree.Kind.METHOD) { |
|
158 MethodTree mt = (MethodTree) mem; |
|
159 if (isDoIt(mt.getName())) { |
|
160 List<? extends StatementTree> stmts = mt.getBody().getStatements(); |
|
161 if (!stmts.isEmpty()) { |
|
162 return stmts.get(0); |
|
163 } |
|
164 } |
|
165 } |
|
166 } |
|
167 } |
|
168 return null; |
|
169 } |
|
170 |
|
171 VariableTree firstVariable() { |
|
172 if (firstClass() != null) { |
|
173 for (Tree mem : firstClass().getMembers()) { |
|
174 if (mem.getKind() == Tree.Kind.VARIABLE) { |
|
175 VariableTree vt = (VariableTree) mem; |
|
176 return vt; |
|
177 } |
|
178 } |
|
179 } |
|
180 return null; |
|
181 } |
|
182 |
|
183 private ClassTree computeFirstClass() { |
|
184 if (cuTree() == null) { |
|
185 return null; |
|
186 } |
|
187 for (Tree decl : cuTree().getTypeDecls()) { |
|
188 if (decl.getKind() == Tree.Kind.CLASS || decl.getKind() == Tree.Kind.INTERFACE) { |
|
189 return (ClassTree) decl; |
|
190 } |
|
191 } |
|
192 return null; |
|
193 } |
|
194 |
|
195 ExpressionInfo typeOfReturnStatement(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) { |
|
196 ExpressionInfo ei = new ExpressionInfo(); |
|
197 Tree unitTree = firstStatement(); |
|
198 if (unitTree instanceof ReturnTree) { |
|
199 ei.tree = ((ReturnTree) unitTree).getExpression(); |
|
200 if (ei.tree != null) { |
|
201 TreePath viPath = trees().getPath(cuTree(), ei.tree); |
|
202 if (viPath != null) { |
|
203 TypeMirror tm = trees().getTypeMirror(viPath); |
|
204 if (tm != null) { |
|
205 Type type = (Type)tm; |
|
206 TypePrinter tp = new TypePrinter(messages, fullClassNameAndPackageToClass, type); |
|
207 ei.typeName = tp.visit(type, Locale.getDefault()); |
|
208 switch (tm.getKind()) { |
|
209 case VOID: |
|
210 case NONE: |
|
211 case ERROR: |
|
212 case OTHER: |
|
213 break; |
|
214 case NULL: |
|
215 ei.isNonVoid = true; |
|
216 ei.typeName = OBJECT_TYPE; |
|
217 break; |
|
218 default: { |
|
219 ei.isNonVoid = true; |
|
220 break; |
|
221 |
|
222 } |
|
223 } |
|
224 } |
|
225 } |
|
226 } |
|
227 } |
|
228 return ei; |
|
229 } |
|
230 |
|
231 String typeOfMethod() { |
|
232 Tree unitTree = firstClassMember(); |
|
233 if (unitTree instanceof JCMethodDecl) { |
|
234 JCMethodDecl mtree = (JCMethodDecl) unitTree; |
|
235 Type mt = types().erasure(mtree.type); |
|
236 if (mt instanceof MethodType) { |
|
237 return signature(types(), (MethodType) mt); |
|
238 } |
|
239 } |
|
240 return null; |
|
241 } |
|
242 |
|
243 static String signature(Types types, MethodType mt) { |
|
244 TDSignatureGenerator sg = new TDSignatureGenerator(types); |
|
245 sg.assembleSig(mt); |
|
246 return sg.toString(); |
|
247 } |
|
248 |
|
249 /** |
|
250 * Signature Generation |
|
251 */ |
|
252 private static class TDSignatureGenerator extends Types.SignatureGenerator { |
|
253 |
|
254 /** |
|
255 * An output buffer for type signatures. |
|
256 */ |
|
257 StringBuilder sb = new StringBuilder(); |
|
258 |
|
259 TDSignatureGenerator(Types types) { |
|
260 super(types); |
|
261 } |
|
262 |
|
263 @Override |
|
264 protected void append(char ch) { |
|
265 sb.append(ch); |
|
266 } |
|
267 |
|
268 @Override |
|
269 protected void append(byte[] ba) { |
|
270 sb.append(new String(ba)); |
|
271 } |
|
272 |
|
273 @Override |
|
274 protected void append(Name name) { |
|
275 sb.append(name); |
|
276 } |
|
277 |
|
278 @Override |
|
279 public String toString() { |
|
280 return sb.toString(); |
|
281 } |
|
282 } |
|
283 } |