|
1 |
| package edu.rice.cs.dynamicjava.symbol; |
|
2 |
| |
|
3 |
| import java.util.Collections; |
|
4 |
| import java.util.List; |
|
5 |
| import java.util.LinkedList; |
|
6 |
| import edu.rice.cs.plt.lambda.Thunk; |
|
7 |
| import edu.rice.cs.plt.lambda.LazyThunk; |
|
8 |
| import edu.rice.cs.plt.lambda.Box; |
|
9 |
| import edu.rice.cs.plt.tuple.Option; |
|
10 |
| import edu.rice.cs.plt.tuple.Pair; |
|
11 |
| import edu.rice.cs.plt.iter.IterUtil; |
|
12 |
| |
|
13 |
| import koala.dynamicjava.tree.*; |
|
14 |
| import koala.dynamicjava.tree.tiger.*; |
|
15 |
| import koala.dynamicjava.tree.visitor.*; |
|
16 |
| import koala.dynamicjava.interpreter.NodeProperties; |
|
17 |
| import koala.dynamicjava.interpreter.error.ExecutionError; |
|
18 |
| |
|
19 |
| import edu.rice.cs.dynamicjava.symbol.type.Type; |
|
20 |
| import edu.rice.cs.dynamicjava.symbol.type.ClassType; |
|
21 |
| import edu.rice.cs.dynamicjava.symbol.type.VariableType; |
|
22 |
| import edu.rice.cs.dynamicjava.symbol.type.SimpleClassType; |
|
23 |
| import edu.rice.cs.dynamicjava.Options; |
|
24 |
| import edu.rice.cs.dynamicjava.interpreter.TreeClassLoader; |
|
25 |
| import edu.rice.cs.dynamicjava.interpreter.RuntimeBindings; |
|
26 |
| import edu.rice.cs.dynamicjava.interpreter.EvaluatorException; |
|
27 |
| import edu.rice.cs.dynamicjava.interpreter.CheckerException; |
|
28 |
| import edu.rice.cs.plt.lambda.WrappedException; |
|
29 |
| |
|
30 |
| import static edu.rice.cs.plt.debug.DebugUtil.debug; |
|
31 |
| |
|
32 |
| |
|
33 |
| |
|
34 |
| |
|
35 |
| |
|
36 |
| |
|
37 |
| |
|
38 |
| |
|
39 |
| |
|
40 |
| |
|
41 |
| |
|
42 |
| |
|
43 |
| |
|
44 |
| public class TreeClass implements DJClass { |
|
45 |
| |
|
46 |
| private static final Type RUNTIME_BINDINGS_TYPE = |
|
47 |
| new SimpleClassType(SymbolUtil.wrapClass(RuntimeBindings.class)); |
|
48 |
| |
|
49 |
| private final String _fullName; |
|
50 |
| private final DJClass _declaring; |
|
51 |
| private final Access.Module _accessModule; |
|
52 |
| private final Node _ast; |
|
53 |
| private final ModifierSet _mods; |
|
54 |
| private final Thunk<Class<?>> _loaded; |
|
55 |
| private final List<TreeConstructor> _constructors; |
|
56 |
| private final List<TreeField> _fields; |
|
57 |
| private final List<TreeMethod> _methods; |
|
58 |
| private final List<TreeClass> _classes; |
|
59 |
| private final Options _opt; |
|
60 |
| |
|
61 |
| |
|
62 |
| |
|
63 |
| |
|
64 |
| |
|
65 |
| |
|
66 |
| |
|
67 |
| |
|
68 |
| |
|
69 |
| |
|
70 |
| |
|
71 |
| |
|
72 |
| |
|
73 |
89
| public TreeClass(String fullName, DJClass declaring, Access.Module accessModule, final Node ast,
|
|
74 |
| final TreeClassLoader loader, Options opt) { |
|
75 |
89
| _fullName = fullName;
|
|
76 |
89
| _declaring = declaring;
|
|
77 |
89
| _accessModule = (accessModule == null) ? this : accessModule;
|
|
78 |
89
| _ast = ast;
|
|
79 |
89
| if (_ast instanceof TypeDeclaration) { _mods = ((TypeDeclaration) _ast).getModifiers(); }
|
|
80 |
0
| else { _mods = ModifierSet.make(); }
|
|
81 |
89
| _loaded = LazyThunk.make(new Thunk<Class<?>>() {
|
|
82 |
35
| public Class<?> value() {
|
|
83 |
35
| try { return loader.loadClass(_fullName); }
|
|
84 |
0
| catch (ClassNotFoundException e) { throw new RuntimeException("Error loading class", e); }
|
|
85 |
| |
|
86 |
| catch (LinkageError e) { |
|
87 |
| |
|
88 |
| |
|
89 |
0
| if (e instanceof IllegalAccessError) {
|
|
90 |
| |
|
91 |
0
| String msg = e.getMessage();
|
|
92 |
0
| final String PREFIX = "class ";
|
|
93 |
0
| final String[] INFIX = new String[] { " cannot access its superclass ",
|
|
94 |
| " cannot access its superinterface " }; |
|
95 |
0
| final String[] ERROR_MSGS = new String[] { "class.cannot.access.superclass",
|
|
96 |
| "class.cannot.access.superinterface" }; |
|
97 |
0
| if (msg.startsWith(PREFIX)) {
|
|
98 |
0
| for (int i=0; i<INFIX.length; ++i) {
|
|
99 |
0
| final String infix = INFIX[i];
|
|
100 |
0
| int infixPos = msg.indexOf(infix);
|
|
101 |
0
| if ((infixPos>=0) && (infixPos>=PREFIX.length())) {
|
|
102 |
0
| String className0 = msg.substring(PREFIX.length(), infixPos).trim();
|
|
103 |
0
| String className1 = msg.substring(infixPos+infix.length()).trim();
|
|
104 |
0
| koala.dynamicjava.interpreter.NodeProperties.setErrorStrings(ast, className0, className1);
|
|
105 |
0
| ExecutionError ee = new ExecutionError(ERROR_MSGS[i], ast);
|
|
106 |
0
| throw new WrappedException(new CheckerException(ee));
|
|
107 |
| } |
|
108 |
| } |
|
109 |
| } |
|
110 |
| } |
|
111 |
0
| throw new RuntimeException("Error loading class", e);
|
|
112 |
| } |
|
113 |
| } |
|
114 |
| }); |
|
115 |
89
| _constructors = new LinkedList<TreeConstructor>();
|
|
116 |
89
| _fields = new LinkedList<TreeField>();
|
|
117 |
89
| _methods = new LinkedList<TreeMethod>();
|
|
118 |
89
| _classes = new LinkedList<TreeClass>();
|
|
119 |
89
| _opt = opt;
|
|
120 |
89
| loader.registerTree(this);
|
|
121 |
89
| tagSignature();
|
|
122 |
89
| extractMembers(loader);
|
|
123 |
| } |
|
124 |
| |
|
125 |
| |
|
126 |
89
| private void tagSignature() {
|
|
127 |
89
| if (_ast instanceof TypeDeclaration) {
|
|
128 |
89
| TypeDeclaration td = (TypeDeclaration) _ast;
|
|
129 |
| |
|
130 |
89
| List<TypeParameter> tparams = td.getTypeParams().unwrap(Collections.<TypeParameter>emptyList());
|
|
131 |
89
| for (TypeParameter p : tparams) {
|
|
132 |
69
| BoundedSymbol tempBounds = new BoundedSymbol(new Object(), p.getRepresentation(),
|
|
133 |
| TypeSystem.OBJECT, TypeSystem.NULL); |
|
134 |
69
| NodeProperties.setTypeVariable(p, new VariableType(tempBounds));
|
|
135 |
| } |
|
136 |
| |
|
137 |
89
| if (td instanceof ClassDeclaration) {
|
|
138 |
89
| NodeProperties.setType(((ClassDeclaration) td).getSuperclass(), TypeSystem.OBJECT);
|
|
139 |
| } |
|
140 |
89
| if (td.getInterfaces() != null) {
|
|
141 |
1
| for (ReferenceTypeName tn : td.getInterfaces()) { NodeProperties.setType(tn, TypeSystem.OBJECT); }
|
|
142 |
| } |
|
143 |
| } |
|
144 |
| } |
|
145 |
| |
|
146 |
89
| private void extractMembers(final TreeClassLoader loader) {
|
|
147 |
89
| Iterable<Node> members = IterUtil.empty();
|
|
148 |
89
| if (_ast instanceof TypeDeclaration) { members = ((TypeDeclaration) _ast).getMembers(); }
|
|
149 |
0
| else if (_ast instanceof AnonymousAllocation) {
|
|
150 |
0
| members = ((AnonymousAllocation) _ast).getMembers();
|
|
151 |
| } |
|
152 |
0
| else if (_ast instanceof AnonymousInnerAllocation) {
|
|
153 |
0
| members = ((AnonymousInnerAllocation) _ast).getMembers();
|
|
154 |
| } |
|
155 |
89
| for (Node n : members) {
|
|
156 |
250
| n.acceptVisitor(new AbstractVisitor<Void>() {
|
|
157 |
0
| @Override public Void defaultCase(Node n) { return null; }
|
|
158 |
0
| @Override public Void visit(ClassDeclaration d) {
|
|
159 |
0
| TreeClass c = new TreeClass(_fullName + "$" + d.getName(), TreeClass.this, _accessModule, d, loader, _opt);
|
|
160 |
0
| NodeProperties.setDJClass(d, c);
|
|
161 |
0
| _classes.add(c);
|
|
162 |
0
| return null;
|
|
163 |
| } |
|
164 |
0
| @Override public Void visit(InterfaceDeclaration d) {
|
|
165 |
0
| TreeClass c = new TreeClass(_fullName + "$" + d.getName(), TreeClass.this, _accessModule, d, loader, _opt);
|
|
166 |
0
| NodeProperties.setDJClass(d, c);
|
|
167 |
0
| _classes.add(c);
|
|
168 |
0
| return null;
|
|
169 |
| } |
|
170 |
69
| @Override public Void visit(ConstructorDeclaration d) {
|
|
171 |
69
| TreeConstructor k = new ExplicitTreeConstructor(d);
|
|
172 |
69
| NodeProperties.setConstructor(d, k);
|
|
173 |
69
| _constructors.add(k);
|
|
174 |
69
| return null;
|
|
175 |
| } |
|
176 |
158
| @Override public Void visit(MethodDeclaration d) {
|
|
177 |
158
| TreeMethod m = new TreeMethod(d);
|
|
178 |
158
| NodeProperties.setMethod(d, m);
|
|
179 |
158
| _methods.add(m);
|
|
180 |
158
| return null;
|
|
181 |
| } |
|
182 |
23
| @Override public Void visit(FieldDeclaration d) {
|
|
183 |
23
| TreeField f = new TreeField(d);
|
|
184 |
23
| NodeProperties.setField(d, f);
|
|
185 |
23
| _fields.add(f);
|
|
186 |
23
| return null;
|
|
187 |
| } |
|
188 |
| }); |
|
189 |
| } |
|
190 |
89
| if (_constructors.isEmpty() && !(_ast instanceof InterfaceDeclaration)) {
|
|
191 |
20
| _constructors.add(new DefaultTreeConstructor());
|
|
192 |
| } |
|
193 |
| } |
|
194 |
| |
|
195 |
35
| public Node declaration() { return _ast; }
|
|
196 |
| |
|
197 |
0
| public String packageName() {
|
|
198 |
| |
|
199 |
0
| int dot = _fullName.lastIndexOf('.');
|
|
200 |
0
| if (dot == -1) { return ""; }
|
|
201 |
0
| else { return _fullName.substring(0, dot); }
|
|
202 |
| } |
|
203 |
| |
|
204 |
| |
|
205 |
227
| public String fullName() { return _fullName; }
|
|
206 |
| |
|
207 |
2404
| public boolean isAnonymous() { return !(_ast instanceof TypeDeclaration); }
|
|
208 |
| |
|
209 |
1605
| public String declaredName() {
|
|
210 |
1605
| if (_ast instanceof TypeDeclaration) {
|
|
211 |
1605
| return ((TypeDeclaration) _ast).getName();
|
|
212 |
| } |
|
213 |
0
| else { throw new IllegalArgumentException("Anonymous class has no declared name"); }
|
|
214 |
| } |
|
215 |
| |
|
216 |
614
| public boolean isInterface() { return _ast instanceof InterfaceDeclaration; }
|
|
217 |
| |
|
218 |
1573
| public boolean isStatic() {
|
|
219 |
1573
| if (_declaring == null) { return false; }
|
|
220 |
0
| else { return _declaring.isInterface() || isInterface() || _ast instanceof EnumDeclaration || _mods.isStatic(); }
|
|
221 |
| } |
|
222 |
54
| public boolean isAbstract() { return _mods.isAbstract(); }
|
|
223 |
0
| public boolean isFinal() { return _mods.isFinal(); }
|
|
224 |
0
| public Access accessibility() {
|
|
225 |
0
| return (_declaring != null && _declaring.isInterface()) ? Access.PUBLIC : extractAccessibility(_mods);
|
|
226 |
| } |
|
227 |
1042
| public Access.Module accessModule() { return _accessModule; }
|
|
228 |
7
| public boolean hasRuntimeBindingsParams() { return true; }
|
|
229 |
| |
|
230 |
| |
|
231 |
3221
| public DJClass declaringClass() { return _declaring; }
|
|
232 |
| |
|
233 |
| |
|
234 |
2484
| public Iterable<VariableType> declaredTypeParameters() {
|
|
235 |
2484
| List<TypeParameter> paramAsts = Collections.emptyList();
|
|
236 |
2484
| if (_ast instanceof TypeDeclaration) {
|
|
237 |
2484
| paramAsts = ((TypeDeclaration) _ast).getTypeParams().unwrap(paramAsts);
|
|
238 |
| } |
|
239 |
2484
| return IterUtil.mapSnapshot(paramAsts, NodeProperties.NODE_TYPE_VARIABLE);
|
|
240 |
| } |
|
241 |
| |
|
242 |
| |
|
243 |
1237
| public Iterable<Type> declaredSupertypes() {
|
|
244 |
1237
| if (_ast instanceof ClassDeclaration) {
|
|
245 |
1237
| ClassDeclaration cd = (ClassDeclaration) _ast;
|
|
246 |
1237
| Iterable<Type> superIs;
|
|
247 |
1207
| if (cd.getInterfaces() == null) { superIs = IterUtil.empty(); }
|
|
248 |
30
| else { superIs = IterUtil.mapSnapshot(cd.getInterfaces(), NodeProperties.NODE_TYPE); }
|
|
249 |
1237
| return IterUtil.compose(NodeProperties.getType(cd.getSuperclass()), superIs);
|
|
250 |
| } |
|
251 |
0
| else if (_ast instanceof InterfaceDeclaration) {
|
|
252 |
0
| InterfaceDeclaration id = (InterfaceDeclaration) _ast;
|
|
253 |
0
| if (id.getInterfaces() == null) { return IterUtil.empty(); }
|
|
254 |
0
| else { return IterUtil.mapSnapshot(id.getInterfaces(), NodeProperties.NODE_TYPE); }
|
|
255 |
| } |
|
256 |
0
| else if (_ast instanceof AnonymousAllocation) {
|
|
257 |
0
| return IterUtil.singleton(NodeProperties.getType(((AnonymousAllocation) _ast).getCreationType()));
|
|
258 |
| } |
|
259 |
0
| else if (_ast instanceof AnonymousInnerAllocation) {
|
|
260 |
0
| return IterUtil.singleton(NodeProperties.getSuperType(_ast));
|
|
261 |
| } |
|
262 |
0
| else { throw new IllegalArgumentException("Unsupported class AST type"); }
|
|
263 |
| } |
|
264 |
| |
|
265 |
328
| public Iterable<DJField> declaredFields() { return IterUtil.<DJField>immutable(_fields); }
|
|
266 |
| |
|
267 |
100
| public Iterable<DJConstructor> declaredConstructors() { return IterUtil.<DJConstructor>immutable(_constructors); }
|
|
268 |
| |
|
269 |
42
| public Iterable<DJMethod> declaredMethods() { return IterUtil.<DJMethod>immutable(_methods); }
|
|
270 |
| |
|
271 |
639
| public Iterable<DJClass> declaredClasses() { return IterUtil.<DJClass>immutable(_classes); }
|
|
272 |
| |
|
273 |
| |
|
274 |
| |
|
275 |
| |
|
276 |
| |
|
277 |
69
| public Type immediateSuperclass() {
|
|
278 |
69
| if (_ast instanceof ClassDeclaration) {
|
|
279 |
| |
|
280 |
69
| return NodeProperties.getType(((ClassDeclaration)_ast).getSuperclass());
|
|
281 |
| } |
|
282 |
0
| else if (_ast instanceof InterfaceDeclaration) {
|
|
283 |
0
| return TypeSystem.OBJECT;
|
|
284 |
| } |
|
285 |
0
| else if (_ast instanceof AnonymousAllocation) {
|
|
286 |
0
| Type result = NodeProperties.getType(((AnonymousAllocation) _ast).getCreationType());
|
|
287 |
0
| if (result instanceof ClassType && !((ClassType) result).ofClass().isInterface()) {
|
|
288 |
0
| return result;
|
|
289 |
| } |
|
290 |
0
| else { return TypeSystem.OBJECT; }
|
|
291 |
| } |
|
292 |
0
| else if (_ast instanceof AnonymousInnerAllocation) {
|
|
293 |
0
| return NodeProperties.getSuperType(_ast);
|
|
294 |
| } |
|
295 |
0
| else { throw new IllegalArgumentException("Unsupported class AST type"); }
|
|
296 |
| } |
|
297 |
| |
|
298 |
| |
|
299 |
| |
|
300 |
| |
|
301 |
| |
|
302 |
92
| public Class<?> load() { return _loaded.value(); }
|
|
303 |
| |
|
304 |
0
| public String toString() { return "TreeClass(" + _fullName + ")"; }
|
|
305 |
| |
|
306 |
72
| public boolean equals(Object o) {
|
|
307 |
60
| if (this == o) { return true; }
|
|
308 |
0
| else if (!o.getClass().equals(getClass())) { return false; }
|
|
309 |
12
| else { return _ast == ((TreeClass) o)._ast; }
|
|
310 |
| } |
|
311 |
| |
|
312 |
401
| public int hashCode() { return getClass().hashCode() ^ System.identityHashCode(_ast); }
|
|
313 |
| |
|
314 |
| |
|
315 |
| private class TreeField implements DJField { |
|
316 |
| private final FieldDeclaration _f; |
|
317 |
| private final Thunk<DJField> _loaded; |
|
318 |
23
| public TreeField(FieldDeclaration f) {
|
|
319 |
23
| _f = f;
|
|
320 |
23
| _loaded = LazyThunk.make(new Thunk<DJField>() {
|
|
321 |
12
| public DJField value() {
|
|
322 |
12
| DJClass c = SymbolUtil.wrapClass(TreeClass.this.load());
|
|
323 |
12
| for (DJField candidate : c.declaredFields()) {
|
|
324 |
36
| if (TreeField.this.declaredName().equals(candidate.declaredName())) {
|
|
325 |
12
| return candidate;
|
|
326 |
| } |
|
327 |
| } |
|
328 |
| |
|
329 |
0
| debug.logValues(new String[]{"name", "candidates"},
|
|
330 |
| TreeField.this.declaredName(), c.declaredFields()); |
|
331 |
0
| throw new RuntimeException("Can't find field in loaded class");
|
|
332 |
| } |
|
333 |
| }); |
|
334 |
| } |
|
335 |
358
| public String declaredName() { return _f.getName(); }
|
|
336 |
0
| public DJClass declaringClass() { return TreeClass.this; }
|
|
337 |
138
| public Type type() { return NodeProperties.getType(_f.getType()); }
|
|
338 |
115
| public boolean isFinal() { return _f.getModifiers().isFinal() || isInterface(); }
|
|
339 |
69
| public boolean isStatic() { return _f.getModifiers().isStatic() || isInterface(); }
|
|
340 |
322
| public Access accessibility() {
|
|
341 |
322
| return isInterface() ? Access.PUBLIC : extractAccessibility(_f.getModifiers());
|
|
342 |
| } |
|
343 |
0
| public Access.Module accessModule() { return _accessModule; }
|
|
344 |
69
| public Option<Object> constantValue() {
|
|
345 |
69
| if (isFinal() && isStatic()) {
|
|
346 |
0
| Expression init = _f.getInitializer();
|
|
347 |
0
| if (init != null) {
|
|
348 |
0
| if (NodeProperties.hasValue(init)) { return Option.some(NodeProperties.getValue(init)); }
|
|
349 |
| |
|
350 |
| |
|
351 |
| |
|
352 |
0
| else if (init instanceof Literal) { return Option.some(((Literal) init).getValue()); }
|
|
353 |
| } |
|
354 |
| } |
|
355 |
69
| return Option.none();
|
|
356 |
| } |
|
357 |
33
| public Box<Object> boxForReceiver(Object receiver) {
|
|
358 |
33
| return _loaded.value().boxForReceiver(receiver);
|
|
359 |
| } |
|
360 |
0
| public String toString() { return "TreeField(" + declaredName() + ")"; }
|
|
361 |
| } |
|
362 |
| |
|
363 |
| |
|
364 |
| private abstract class TreeConstructor implements DJConstructor { |
|
365 |
| private final Thunk<DJConstructor> _loaded; |
|
366 |
| private final DJClass _outerClass; |
|
367 |
| |
|
368 |
89
| public TreeConstructor() {
|
|
369 |
89
| _loaded = LazyThunk.make(new Thunk<DJConstructor>() {
|
|
370 |
32
| public DJConstructor value() {
|
|
371 |
32
| Iterable<LocalVariable> params = TreeConstructor.this.parameters();
|
|
372 |
32
| if (_outerClass == null) {
|
|
373 |
32
| params = IterUtil.compose(new LocalVariable("", RUNTIME_BINDINGS_TYPE, false), params);
|
|
374 |
| } |
|
375 |
32
| DJClass c = SymbolUtil.wrapClass(TreeClass.this.load());
|
|
376 |
32
| for (DJConstructor candidate : c.declaredConstructors()) {
|
|
377 |
32
| if (paramsMatch(params, candidate.parameters())) {
|
|
378 |
32
| return candidate;
|
|
379 |
| } |
|
380 |
| } |
|
381 |
| |
|
382 |
0
| debug.logValues(new String[]{"params", "candidates"}, params, c.declaredConstructors());
|
|
383 |
0
| throw new RuntimeException("Can't find constructor in loaded class");
|
|
384 |
| } |
|
385 |
| }); |
|
386 |
89
| _outerClass = SymbolUtil.dynamicOuterClass(TreeClass.this);
|
|
387 |
| } |
|
388 |
| |
|
389 |
1
| public String declaredName() { return isAnonymous() ? "<anonymous>" : TreeClass.this.declaredName(); }
|
|
390 |
0
| public DJClass declaringClass() { return TreeClass.this; }
|
|
391 |
0
| public Access.Module accessModule() { return _accessModule; }
|
|
392 |
100
| public Type returnType() { return SymbolUtil.thisType(TreeClass.this); }
|
|
393 |
| |
|
394 |
7
| public DJConstructor declaredSignature() { return this; }
|
|
395 |
39
| public Object evaluate(Object outer, Iterable<Object> args, RuntimeBindings bindings, Options options)
|
|
396 |
| throws EvaluatorException { |
|
397 |
39
| if (_outerClass == null) { args = IterUtil.compose(bindings, args); }
|
|
398 |
39
| return _loaded.value().evaluate(outer, args, bindings, options);
|
|
399 |
| } |
|
400 |
0
| public String toString() { return "TreeConstructor(" + declaredName() + ")"; }
|
|
401 |
| } |
|
402 |
| |
|
403 |
| |
|
404 |
| private class DefaultTreeConstructor extends TreeConstructor { |
|
405 |
22
| public Access accessibility() { return Access.PUBLIC; }
|
|
406 |
44
| public Iterable<VariableType> typeParameters() { return IterUtil.empty(); }
|
|
407 |
38
| public Iterable<LocalVariable> parameters() { return IterUtil.empty(); }
|
|
408 |
22
| public Iterable<Type> thrownTypes() { return IterUtil.empty(); }
|
|
409 |
| } |
|
410 |
| |
|
411 |
| |
|
412 |
| private class ExplicitTreeConstructor extends TreeConstructor { |
|
413 |
| private final ConstructorDeclaration _k; |
|
414 |
69
| public ExplicitTreeConstructor(ConstructorDeclaration k) {
|
|
415 |
69
| _k = k;
|
|
416 |
| } |
|
417 |
124
| public Access accessibility() { return extractAccessibility(_k.getModifiers()); }
|
|
418 |
239
| public Iterable<VariableType> typeParameters() {
|
|
419 |
239
| List<TypeParameter> paramAsts = _k.getTypeParams().unwrap(Collections.<TypeParameter>emptyList());
|
|
420 |
239
| return IterUtil.mapSnapshot(paramAsts, NodeProperties.NODE_TYPE_VARIABLE);
|
|
421 |
| } |
|
422 |
418
| public Iterable<LocalVariable> parameters() {
|
|
423 |
418
| return IterUtil.mapSnapshot(_k.getParameters(), NodeProperties.NODE_VARIABLE);
|
|
424 |
| } |
|
425 |
146
| public Iterable<Type> thrownTypes() {
|
|
426 |
146
| return IterUtil.mapSnapshot(_k.getExceptions(), NodeProperties.NODE_TYPE);
|
|
427 |
| } |
|
428 |
| } |
|
429 |
| |
|
430 |
| |
|
431 |
| private class TreeMethod implements DJMethod { |
|
432 |
| private MethodDeclaration _m; |
|
433 |
| private Thunk<DJMethod> _loaded; |
|
434 |
| |
|
435 |
158
| public TreeMethod(MethodDeclaration m) {
|
|
436 |
158
| _m = m;
|
|
437 |
158
| _loaded = LazyThunk.make(new Thunk<DJMethod>() {
|
|
438 |
27
| public DJMethod value() {
|
|
439 |
27
| Iterable<LocalVariable> params = TreeMethod.this.parameters();
|
|
440 |
27
| if (TreeMethod.this.isStatic()) {
|
|
441 |
0
| params = IterUtil.compose(new LocalVariable("", RUNTIME_BINDINGS_TYPE, false), params);
|
|
442 |
| } |
|
443 |
27
| DJClass c = SymbolUtil.wrapClass(TreeClass.this.load());
|
|
444 |
27
| for (DJMethod candidate : c.declaredMethods()) {
|
|
445 |
70
| if (TreeMethod.this.declaredName().equals(candidate.declaredName()) &&
|
|
446 |
| paramsMatch(params, candidate.parameters())) { |
|
447 |
27
| return candidate;
|
|
448 |
| } |
|
449 |
| } |
|
450 |
| |
|
451 |
0
| debug.logValues(new String[]{"name", "params", "candidates"},
|
|
452 |
| TreeMethod.this.declaredName(), params, c.declaredMethods()); |
|
453 |
0
| throw new RuntimeException("Can't find method in loaded class");
|
|
454 |
| } |
|
455 |
| }); |
|
456 |
| } |
|
457 |
| |
|
458 |
224
| public String declaredName() { return _m.getName(); }
|
|
459 |
0
| public DJClass declaringClass() { return TreeClass.this; }
|
|
460 |
138
| public boolean isStatic() { return _m.getModifiers().isStatic(); }
|
|
461 |
0
| public boolean isAbstract() { return _m.getModifiers().isAbstract() || isInterface(); }
|
|
462 |
0
| public boolean isFinal() { return _m.getModifiers().isFinal(); }
|
|
463 |
54
| public Access accessibility() {
|
|
464 |
54
| return isInterface() ? Access.PUBLIC : extractAccessibility(_m.getModifiers());
|
|
465 |
| } |
|
466 |
0
| public Access.Module accessModule() { return _accessModule; }
|
|
467 |
| |
|
468 |
236
| public Type returnType() { return NodeProperties.getType(_m.getReturnType()); }
|
|
469 |
| |
|
470 |
377
| public Iterable<VariableType> typeParameters() {
|
|
471 |
377
| List<TypeParameter> paramAsts = _m.getTypeParams().unwrap(Collections.<TypeParameter>emptyList());
|
|
472 |
377
| return IterUtil.mapSnapshot(paramAsts, NodeProperties.NODE_TYPE_VARIABLE);
|
|
473 |
| } |
|
474 |
| |
|
475 |
804
| public Iterable<LocalVariable> parameters() {
|
|
476 |
804
| return IterUtil.mapSnapshot(_m.getParameters(), NodeProperties.NODE_VARIABLE);
|
|
477 |
| } |
|
478 |
| |
|
479 |
43
| public Iterable<Type> thrownTypes() {
|
|
480 |
43
| return IterUtil.mapSnapshot(_m.getExceptions(), NodeProperties.NODE_TYPE);
|
|
481 |
| } |
|
482 |
| |
|
483 |
0
| public DJMethod declaredSignature() { return this; }
|
|
484 |
| |
|
485 |
29
| public Object evaluate(Object receiver, Iterable<Object> args, RuntimeBindings bindings, Options options)
|
|
486 |
| throws EvaluatorException { |
|
487 |
0
| if (isStatic()) { args = IterUtil.compose(bindings, args); }
|
|
488 |
29
| return _loaded.value().evaluate(receiver, args, bindings, options);
|
|
489 |
| } |
|
490 |
| |
|
491 |
0
| public String toString() { return "TreeMethod(" + declaredName() + ")"; }
|
|
492 |
| } |
|
493 |
| |
|
494 |
| |
|
495 |
| |
|
496 |
500
| private static Access extractAccessibility(ModifierSet mods) {
|
|
497 |
178
| if (mods.isPublic()) { return Access.PUBLIC; }
|
|
498 |
0
| else if (mods.isProtected()) { return Access.PROTECTED; }
|
|
499 |
322
| else if (mods.isPrivate()) { return Access.PRIVATE; }
|
|
500 |
0
| else { return Access.PACKAGE; }
|
|
501 |
| } |
|
502 |
| |
|
503 |
| |
|
504 |
| |
|
505 |
| |
|
506 |
| |
|
507 |
59
| private boolean paramsMatch(Iterable<LocalVariable> p1, Iterable<LocalVariable> p2) {
|
|
508 |
59
| if (IterUtil.sizeOf(p1) == IterUtil.sizeOf(p2)) {
|
|
509 |
59
| TypeSystem ts = _opt.typeSystem();
|
|
510 |
59
| for (Pair<LocalVariable, LocalVariable> vars : IterUtil.zip(p1, p2)) {
|
|
511 |
70
| Thunk<Class<?>> c1 = ts.erasedClass(vars.first().type());
|
|
512 |
70
| Thunk<Class<?>> c2 = ts.erasedClass(vars.second().type());
|
|
513 |
70
| if (!c1.value().equals(c2.value())) {
|
|
514 |
0
| return false;
|
|
515 |
| } |
|
516 |
| } |
|
517 |
59
| return true;
|
|
518 |
| } |
|
519 |
0
| else { return false; }
|
|
520 |
| } |
|
521 |
| |
|
522 |
| } |