|
1 |
| package edu.rice.cs.dynamicjava.interpreter; |
|
2 |
| |
|
3 |
| import java.util.*; |
|
4 |
| |
|
5 |
| import edu.rice.cs.plt.collect.IndexedRelation; |
|
6 |
| import edu.rice.cs.plt.collect.Relation; |
|
7 |
| import edu.rice.cs.plt.iter.IterUtil; |
|
8 |
| import edu.rice.cs.plt.iter.SequenceIterator; |
|
9 |
| import edu.rice.cs.plt.lambda.Lambda; |
|
10 |
| import edu.rice.cs.plt.lambda.LambdaUtil; |
|
11 |
| import edu.rice.cs.plt.text.TextUtil; |
|
12 |
| |
|
13 |
| import edu.rice.cs.dynamicjava.Options; |
|
14 |
| import edu.rice.cs.dynamicjava.symbol.*; |
|
15 |
| import edu.rice.cs.dynamicjava.symbol.type.IntersectionType; |
|
16 |
| import edu.rice.cs.dynamicjava.symbol.type.Type; |
|
17 |
| import edu.rice.cs.dynamicjava.symbol.type.ClassType; |
|
18 |
| |
|
19 |
| import static edu.rice.cs.plt.debug.DebugUtil.debug; |
|
20 |
| |
|
21 |
| |
|
22 |
| |
|
23 |
| |
|
24 |
| |
|
25 |
| public class ImportContext extends DelegatingContext { |
|
26 |
| |
|
27 |
| private final TypeContext _next; |
|
28 |
| private final Options _opt; |
|
29 |
| private final String _currentPackage; |
|
30 |
| private final Iterator<Integer> _anonymousCounter; |
|
31 |
| |
|
32 |
| |
|
33 |
| |
|
34 |
| |
|
35 |
| private final HashSet<String> _onDemandPackages; |
|
36 |
| |
|
37 |
| private final HashSet<DJClass> _onDemandClasses; |
|
38 |
| |
|
39 |
| private final HashSet<DJClass> _staticOnDemandClasses; |
|
40 |
| |
|
41 |
| |
|
42 |
| private final HashMap<String, DJClass> _importedTopLevelClasses; |
|
43 |
| |
|
44 |
| private final HashMap<String, DJClass> _importedMemberClasses; |
|
45 |
| |
|
46 |
| private final HashMap<String, DJClass> _importedFields; |
|
47 |
| |
|
48 |
| private final Relation<String, DJClass> _importedMethods; |
|
49 |
| |
|
50 |
| |
|
51 |
| |
|
52 |
| |
|
53 |
| |
|
54 |
183
| public ImportContext(ClassLoader loader, Options opt) {
|
|
55 |
183
| this(new LibraryContext(SymbolUtil.classLibrary(loader)), opt);
|
|
56 |
| } |
|
57 |
| |
|
58 |
| |
|
59 |
| |
|
60 |
| |
|
61 |
| |
|
62 |
183
| public ImportContext(TypeContext next, Options opt) {
|
|
63 |
183
| super(next);
|
|
64 |
183
| _next = next;
|
|
65 |
183
| _opt = opt;
|
|
66 |
183
| _currentPackage = "";
|
|
67 |
183
| _anonymousCounter = new SequenceIterator<Integer>(1, LambdaUtil.INCREMENT_INT);
|
|
68 |
183
| _onDemandPackages = new HashSet<String>();
|
|
69 |
183
| _onDemandClasses = new HashSet<DJClass>();
|
|
70 |
183
| _staticOnDemandClasses = new HashSet<DJClass>();
|
|
71 |
183
| _importedTopLevelClasses = new HashMap<String, DJClass>();
|
|
72 |
183
| _importedMemberClasses = new HashMap<String, DJClass>();
|
|
73 |
183
| _importedFields = new HashMap<String, DJClass>();
|
|
74 |
183
| _importedMethods = new IndexedRelation<String, DJClass>(false);
|
|
75 |
| |
|
76 |
183
| _onDemandPackages.add("java.lang");
|
|
77 |
| } |
|
78 |
| |
|
79 |
9
| private ImportContext(ImportContext copy) {
|
|
80 |
9
| this(copy._next, copy._currentPackage, copy);
|
|
81 |
| } |
|
82 |
| |
|
83 |
9
| @SuppressWarnings("unchecked")
|
|
84 |
| private ImportContext(TypeContext next, String currentPackage, ImportContext bindings) { |
|
85 |
9
| super(next);
|
|
86 |
9
| _next = next;
|
|
87 |
9
| _opt = bindings._opt;
|
|
88 |
9
| _currentPackage = currentPackage;
|
|
89 |
9
| _anonymousCounter = bindings._anonymousCounter;
|
|
90 |
9
| _onDemandPackages = (HashSet<String>) bindings._onDemandPackages.clone();
|
|
91 |
9
| _onDemandClasses = (HashSet<DJClass>) bindings._onDemandClasses.clone();
|
|
92 |
9
| _staticOnDemandClasses = (HashSet<DJClass>) bindings._staticOnDemandClasses.clone();
|
|
93 |
9
| _importedTopLevelClasses = (HashMap<String, DJClass>) bindings._importedTopLevelClasses.clone();
|
|
94 |
9
| _importedMemberClasses = (HashMap<String, DJClass>) bindings._importedMemberClasses.clone();
|
|
95 |
9
| _importedFields = (HashMap<String, DJClass>) bindings._importedFields.clone();
|
|
96 |
9
| _importedMethods = new IndexedRelation<String, DJClass>(false);
|
|
97 |
9
| _importedMethods.addAll(bindings._importedMethods);
|
|
98 |
| } |
|
99 |
| |
|
100 |
0
| protected TypeContext duplicate(TypeContext next) {
|
|
101 |
0
| return new ImportContext(next, _currentPackage, this);
|
|
102 |
| } |
|
103 |
| |
|
104 |
| |
|
105 |
| |
|
106 |
| |
|
107 |
| |
|
108 |
0
| @Override public TypeContext setPackage(String name) { return new ImportContext(_next, name, this); }
|
|
109 |
| |
|
110 |
| |
|
111 |
9
| @Override public TypeContext importTopLevelClasses(String pkg) {
|
|
112 |
9
| ImportContext result = new ImportContext(this);
|
|
113 |
9
| result._onDemandPackages.add(pkg);
|
|
114 |
9
| return result;
|
|
115 |
| } |
|
116 |
| |
|
117 |
| |
|
118 |
0
| @Override public TypeContext importMemberClasses(DJClass outer) {
|
|
119 |
0
| ImportContext result = new ImportContext(this);
|
|
120 |
0
| result._onDemandClasses.add(outer);
|
|
121 |
0
| return result;
|
|
122 |
| } |
|
123 |
| |
|
124 |
| |
|
125 |
0
| @Override public TypeContext importStaticMembers(DJClass c) {
|
|
126 |
0
| ImportContext result = new ImportContext(this);
|
|
127 |
0
| result._staticOnDemandClasses.add(c);
|
|
128 |
0
| return result;
|
|
129 |
| } |
|
130 |
| |
|
131 |
| |
|
132 |
0
| @Override public TypeContext importTopLevelClass(DJClass c) {
|
|
133 |
0
| ImportContext result = new ImportContext(this);
|
|
134 |
0
| String name = c.declaredName();
|
|
135 |
| |
|
136 |
0
| result._importedMemberClasses.remove(name);
|
|
137 |
0
| result._importedTopLevelClasses.put(name, c);
|
|
138 |
0
| return result;
|
|
139 |
| } |
|
140 |
| |
|
141 |
| |
|
142 |
0
| @Override public TypeContext importMemberClass(DJClass outer, String name) {
|
|
143 |
0
| ImportContext result = new ImportContext(this);
|
|
144 |
| |
|
145 |
0
| result._importedTopLevelClasses.remove(name);
|
|
146 |
0
| result._importedMemberClasses.put(name, outer);
|
|
147 |
0
| return result;
|
|
148 |
| } |
|
149 |
| |
|
150 |
| |
|
151 |
0
| @Override public TypeContext importField(DJClass c, String name) {
|
|
152 |
0
| ImportContext result = new ImportContext(this);
|
|
153 |
| |
|
154 |
0
| result._importedFields.put(name, c);
|
|
155 |
0
| return result;
|
|
156 |
| } |
|
157 |
| |
|
158 |
| |
|
159 |
0
| @Override public TypeContext importMethod(DJClass c, String name) {
|
|
160 |
0
| ImportContext result = new ImportContext(this);
|
|
161 |
0
| result._importedMethods.add(name, c);
|
|
162 |
0
| return result;
|
|
163 |
| } |
|
164 |
| |
|
165 |
| |
|
166 |
| |
|
167 |
| |
|
168 |
54
| @Override public boolean typeExists(String name, TypeSystem ts) {
|
|
169 |
54
| return importsTopLevelClass(name, ts) || importsMemberClass(name, ts) || super.typeExists(name, ts);
|
|
170 |
| } |
|
171 |
| |
|
172 |
0
| @Override public boolean topLevelClassExists(String name, TypeSystem ts) {
|
|
173 |
0
| return importsTopLevelClass(name, ts) || (!importsMemberClass(name, ts) && super.topLevelClassExists(name, ts));
|
|
174 |
| } |
|
175 |
| |
|
176 |
2028
| @Override public DJClass getTopLevelClass(String name, TypeSystem ts) throws AmbiguousNameException {
|
|
177 |
2028
| DJClass result = importedTopLevelClass(name, ts);
|
|
178 |
2028
| return (result == null && !importsMemberClass(name, ts)) ? super.getTopLevelClass(name, ts) : result;
|
|
179 |
| } |
|
180 |
| |
|
181 |
522
| private boolean importsTopLevelClass(String name, TypeSystem ts) {
|
|
182 |
522
| try { return importedTopLevelClass(name, ts) != null; }
|
|
183 |
0
| catch (AmbiguousNameException e) { return true; }
|
|
184 |
| } |
|
185 |
| |
|
186 |
2550
| private DJClass importedTopLevelClass(String name, TypeSystem ts) throws AmbiguousNameException {
|
|
187 |
2550
| DJClass result = null;
|
|
188 |
2550
| if (!TextUtil.contains(name, '.')) {
|
|
189 |
1793
| result = _importedTopLevelClasses.get(name);
|
|
190 |
1793
| if (result == null) {
|
|
191 |
1793
| result = super.getTopLevelClass(makeClassName(name), ts);
|
|
192 |
1793
| if (result == null) {
|
|
193 |
1367
| LinkedList<String> onDemandNames = new LinkedList<String>();
|
|
194 |
1367
| for (String p : _onDemandPackages) {
|
|
195 |
1473
| String fullName = p + "." + name;
|
|
196 |
890
| if (super.topLevelClassExists(fullName, ts)) { onDemandNames.add(fullName); }
|
|
197 |
| } |
|
198 |
0
| if (onDemandNames.size() > 1) { throw new AmbiguousNameException(); }
|
|
199 |
890
| else if (onDemandNames.size() == 1) { result = super.getTopLevelClass(onDemandNames.get(0), ts); }
|
|
200 |
| } |
|
201 |
| } |
|
202 |
1793
| if (result != null && (_opt.enforcePrivateAccess() || _opt.enforceAllAccess())) {
|
|
203 |
0
| if (!result.accessibility().equals(Access.PUBLIC) &&
|
|
204 |
| !_currentPackage.equals(result.accessModule().packageName())) { |
|
205 |
0
| result = null;
|
|
206 |
| } |
|
207 |
| } |
|
208 |
| } |
|
209 |
2550
| return result;
|
|
210 |
| } |
|
211 |
| |
|
212 |
0
| @Override public boolean memberClassExists(String name, TypeSystem ts) {
|
|
213 |
0
| return importsMemberClass(name, ts) || (!importsTopLevelClass(name, ts) && super.memberClassExists(name, ts));
|
|
214 |
| } |
|
215 |
| |
|
216 |
468
| @Override public ClassType typeContainingMemberClass(String name, TypeSystem ts) throws AmbiguousNameException {
|
|
217 |
468
| ClassType result = importedMemberClassType(name, ts);
|
|
218 |
468
| return (result == null && !importsTopLevelClass(name, ts)) ? super.typeContainingMemberClass(name, ts) : result;
|
|
219 |
| } |
|
220 |
| |
|
221 |
766
| private boolean importsMemberClass(String name, TypeSystem ts) {
|
|
222 |
766
| try { return importedMemberClassType(name, ts) != null; }
|
|
223 |
0
| catch (AmbiguousNameException e) { return true; }
|
|
224 |
| } |
|
225 |
| |
|
226 |
1234
| private ClassType importedMemberClassType(String name, TypeSystem ts) throws AmbiguousNameException {
|
|
227 |
1234
| DJClass explicitImport = _importedMemberClasses.get(name);
|
|
228 |
1234
| ClassType result = explicitImport == null ? null : ts.makeClassType(explicitImport);
|
|
229 |
1234
| if (result == null) {
|
|
230 |
1234
| LinkedList<ClassType> onDemandMatches = new LinkedList<ClassType>();
|
|
231 |
1234
| for (DJClass c : _onDemandClasses) {
|
|
232 |
0
| ClassType t = ts.makeClassType(c);
|
|
233 |
| |
|
234 |
| |
|
235 |
| |
|
236 |
0
| if (ts.containsClass(t, name, accessModule())) { onDemandMatches.add(t); }
|
|
237 |
| } |
|
238 |
1234
| for (DJClass c : _staticOnDemandClasses) {
|
|
239 |
0
| ClassType t = ts.makeClassType(c);
|
|
240 |
0
| if (ts.containsStaticClass(t, name, accessModule())) { onDemandMatches.add(t); }
|
|
241 |
| } |
|
242 |
0
| if (onDemandMatches.size() > 1) { throw new AmbiguousNameException(); }
|
|
243 |
0
| else if (onDemandMatches.size() == 1) { result = onDemandMatches.getFirst(); }
|
|
244 |
1234
| if (result == null) {
|
|
245 |
1234
| result = super.typeContainingMemberClass(name, ts);
|
|
246 |
| } |
|
247 |
| } |
|
248 |
1234
| return result;
|
|
249 |
| } |
|
250 |
| |
|
251 |
| |
|
252 |
| |
|
253 |
0
| @Override public boolean variableExists(String name, TypeSystem ts) {
|
|
254 |
0
| return importsField(name, ts) || super.variableExists(name, ts);
|
|
255 |
| } |
|
256 |
| |
|
257 |
54
| @Override public boolean fieldExists(String name, TypeSystem ts) {
|
|
258 |
54
| return importsField(name, ts) || super.fieldExists(name, ts);
|
|
259 |
| } |
|
260 |
| |
|
261 |
0
| @Override public ClassType typeContainingField(String name, TypeSystem ts) throws AmbiguousNameException {
|
|
262 |
0
| ClassType result = importedFieldType(name, ts);
|
|
263 |
0
| return (result == null) ? super.typeContainingField(name, ts) : result;
|
|
264 |
| } |
|
265 |
| |
|
266 |
54
| @Override public boolean localVariableExists(String name, TypeSystem ts) {
|
|
267 |
54
| return !importsField(name, ts) && super.localVariableExists(name, ts);
|
|
268 |
| } |
|
269 |
| |
|
270 |
0
| @Override public LocalVariable getLocalVariable(String name, TypeSystem ts) {
|
|
271 |
0
| return importsField(name, ts) ? null : super.getLocalVariable(name, ts);
|
|
272 |
| } |
|
273 |
| |
|
274 |
108
| private boolean importsField(String name, TypeSystem ts) {
|
|
275 |
108
| try { return importedFieldType(name, ts) != null; }
|
|
276 |
0
| catch (AmbiguousNameException e) { return true; }
|
|
277 |
| } |
|
278 |
| |
|
279 |
108
| private ClassType importedFieldType(String name, TypeSystem ts) throws AmbiguousNameException {
|
|
280 |
108
| DJClass explicitImport = _importedFields.get(name);
|
|
281 |
108
| ClassType result = explicitImport == null ? null : ts.makeClassType(explicitImport);
|
|
282 |
108
| if (result == null) {
|
|
283 |
108
| LinkedList<ClassType> onDemandMatches = new LinkedList<ClassType>();
|
|
284 |
108
| for (DJClass c : _staticOnDemandClasses) {
|
|
285 |
0
| ClassType t = ts.makeClassType(c);
|
|
286 |
0
| if (ts.containsStaticField(t, name, accessModule())) { onDemandMatches.add(t); }
|
|
287 |
| } |
|
288 |
0
| if (onDemandMatches.size() > 1) { throw new AmbiguousNameException(); }
|
|
289 |
0
| else if (onDemandMatches.size() == 1) { result = onDemandMatches.getFirst(); }
|
|
290 |
108
| if (result == null) {
|
|
291 |
108
| result = super.typeContainingField(name, ts);
|
|
292 |
| } |
|
293 |
| } |
|
294 |
108
| return result;
|
|
295 |
| } |
|
296 |
| |
|
297 |
| |
|
298 |
| |
|
299 |
| |
|
300 |
0
| @Override public boolean functionExists(String name, TypeSystem ts) {
|
|
301 |
0
| return importsMethod(name, ts) || super.functionExists(name, ts);
|
|
302 |
| } |
|
303 |
| |
|
304 |
0
| @Override public boolean methodExists(String name, TypeSystem ts) {
|
|
305 |
0
| return importsMethod(name, ts) || super.methodExists(name, ts);
|
|
306 |
| } |
|
307 |
| |
|
308 |
0
| @Override public Type typeContainingMethod(String name, TypeSystem ts) {
|
|
309 |
0
| Type result = importedMethodType(name, ts);
|
|
310 |
0
| return (result == null) ? super.typeContainingMethod(name, ts) : result;
|
|
311 |
| } |
|
312 |
| |
|
313 |
0
| @Override public boolean localFunctionExists(String name, TypeSystem ts) {
|
|
314 |
0
| return !importsMethod(name, ts) && super.localFunctionExists(name, ts);
|
|
315 |
| } |
|
316 |
| |
|
317 |
108
| @Override public Iterable<LocalFunction> getLocalFunctions(String name, TypeSystem ts,
|
|
318 |
| Iterable<LocalFunction> partial) { |
|
319 |
108
| boolean keepLooking = IterUtil.isEmpty(partial) && !importsMethod(name, ts);
|
|
320 |
108
| return keepLooking ? super.getLocalFunctions(name, ts, partial) : partial;
|
|
321 |
| } |
|
322 |
| |
|
323 |
0
| private boolean importsMethod(String name, TypeSystem ts) {
|
|
324 |
0
| return importedMethodType(name, ts) != null;
|
|
325 |
| } |
|
326 |
| |
|
327 |
0
| private Type importedMethodType(String name, final TypeSystem ts) {
|
|
328 |
0
| Iterable<ClassType> matches;
|
|
329 |
0
| Iterable<DJClass> explicitImports = _importedMethods.matchFirst(name);
|
|
330 |
0
| if (!IterUtil.isEmpty(explicitImports)) {
|
|
331 |
0
| matches = IterUtil.mapSnapshot(explicitImports, new Lambda<DJClass, ClassType>() {
|
|
332 |
0
| public ClassType value(DJClass c) { return ts.makeClassType(c); }
|
|
333 |
| }); |
|
334 |
| } |
|
335 |
| else { |
|
336 |
0
| LinkedList<ClassType> onDemandMatches = new LinkedList<ClassType>();
|
|
337 |
0
| for (DJClass c : _staticOnDemandClasses) {
|
|
338 |
0
| ClassType t = ts.makeClassType(c);
|
|
339 |
0
| if (ts.containsStaticMethod(t, name, accessModule())) { onDemandMatches.add(t); }
|
|
340 |
| } |
|
341 |
0
| matches = onDemandMatches;
|
|
342 |
| } |
|
343 |
| |
|
344 |
0
| switch (IterUtil.sizeOf(matches, 2)) {
|
|
345 |
0
| case 0: return null;
|
|
346 |
0
| case 1: return IterUtil.first(matches);
|
|
347 |
0
| default: return new IntersectionType(matches);
|
|
348 |
| } |
|
349 |
| } |
|
350 |
| |
|
351 |
| |
|
352 |
| |
|
353 |
| |
|
354 |
929
| @Override public Access.Module accessModule() { return new TopLevelAccessModule(_currentPackage); }
|
|
355 |
| |
|
356 |
| |
|
357 |
1882
| @Override public String makeClassName(String n) {
|
|
358 |
1882
| return _currentPackage.equals("") ? n : _currentPackage + "." + n;
|
|
359 |
| } |
|
360 |
| |
|
361 |
| |
|
362 |
0
| @Override public String makeAnonymousClassName() {
|
|
363 |
0
| return makeClassName("$" + _anonymousCounter.next().toString());
|
|
364 |
| } |
|
365 |
| |
|
366 |
| |
|
367 |
| |
|
368 |
| |
|
369 |
| |
|
370 |
0
| @Override public DJClass getThis() { return null; }
|
|
371 |
| |
|
372 |
| |
|
373 |
| |
|
374 |
| |
|
375 |
| |
|
376 |
0
| @Override public DJClass getThis(String className) { return null; }
|
|
377 |
| |
|
378 |
108
| @Override public DJClass getThis(Type expected, TypeSystem ts) { return null; }
|
|
379 |
| |
|
380 |
0
| @Override public DJClass initializingClass() { return null; }
|
|
381 |
| |
|
382 |
| |
|
383 |
| |
|
384 |
| |
|
385 |
| |
|
386 |
0
| @Override public Type getReturnType() { return null; }
|
|
387 |
| |
|
388 |
| |
|
389 |
| |
|
390 |
| |
|
391 |
| |
|
392 |
524
| @Override public Iterable<Type> getDeclaredThrownTypes() {
|
|
393 |
| |
|
394 |
524
| return IterUtil.<Type>singleton(TypeSystem.THROWABLE);
|
|
395 |
| } |
|
396 |
| |
|
397 |
| } |