001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.resolve.scopes;
018
019 import com.google.common.collect.*;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.resolve.name.LabelName;
024 import org.jetbrains.jet.lang.resolve.name.Name;
025 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
026 import org.jetbrains.jet.util.CommonSuppliers;
027
028 import java.util.*;
029
030 public class WritableScopeImpl extends WritableScopeWithImports {
031
032 private final Collection<DeclarationDescriptor> allDescriptors = Lists.newArrayList();
033 private final Multimap<Name, DeclarationDescriptor> declaredDescriptorsAccessibleBySimpleName = HashMultimap.create();
034 private boolean allDescriptorsDone = false;
035
036 private Set<ClassDescriptor> allObjectDescriptors = null;
037
038 @NotNull
039 private final DeclarationDescriptor ownerDeclarationDescriptor;
040
041 // FieldNames include "$"
042 @Nullable
043 private Map<Name, PropertyDescriptor> propertyDescriptorsByFieldNames;
044
045 @Nullable
046 private SetMultimap<Name, FunctionDescriptor> functionGroups;
047
048 @Nullable
049 private Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors;
050
051 @Nullable
052 private SetMultimap<Name, VariableDescriptor> propertyGroups;
053
054 @Nullable
055 private Map<Name, NamespaceDescriptor> namespaceAliases;
056
057 @Nullable
058 private Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors;
059
060 @Nullable
061 private Map<Name, ClassDescriptor> objectDescriptors;
062
063 @Nullable
064 private ReceiverParameterDescriptor implicitReceiver;
065
066 public WritableScopeImpl(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner,
067 @NotNull RedeclarationHandler redeclarationHandler, @NotNull String debugName) {
068 super(scope, redeclarationHandler, debugName);
069 this.ownerDeclarationDescriptor = owner;
070 }
071
072 @NotNull
073 @Override
074 public DeclarationDescriptor getContainingDeclaration() {
075 return ownerDeclarationDescriptor;
076 }
077
078 @Override
079 public void importScope(@NotNull JetScope imported) {
080 checkMayWrite();
081 super.importScope(imported);
082 }
083
084 @Override
085 public void importClassifierAlias(@NotNull Name importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) {
086 checkMayWrite();
087
088 allDescriptors.add(classifierDescriptor);
089 super.importClassifierAlias(importedClassifierName, classifierDescriptor);
090 }
091
092 @Override
093 public void importNamespaceAlias(@NotNull Name aliasName, @NotNull NamespaceDescriptor namespaceDescriptor) {
094 checkMayWrite();
095
096 allDescriptors.add(namespaceDescriptor);
097 super.importNamespaceAlias(aliasName, namespaceDescriptor);
098 }
099
100 @Override
101 public void importFunctionAlias(@NotNull Name aliasName, @NotNull FunctionDescriptor functionDescriptor) {
102 checkMayWrite();
103
104 addFunctionDescriptor(functionDescriptor);
105 super.importFunctionAlias(aliasName, functionDescriptor);
106
107 }
108
109 @Override
110 public void importVariableAlias(@NotNull Name aliasName, @NotNull VariableDescriptor variableDescriptor) {
111 checkMayWrite();
112
113 addPropertyDescriptor(variableDescriptor);
114 super.importVariableAlias(aliasName, variableDescriptor);
115 }
116
117 @Override
118 public void clearImports() {
119 checkMayWrite();
120
121 super.clearImports();
122 }
123
124 @NotNull
125 @Override
126 public Collection<DeclarationDescriptor> getAllDescriptors() {
127 checkMayRead();
128
129 if (!allDescriptorsDone) {
130 allDescriptorsDone = true;
131
132 // make sure no descriptors added to allDescriptors collection
133 changeLockLevel(LockLevel.READING);
134
135 allDescriptors.addAll(getWorkerScope().getAllDescriptors());
136 for (JetScope imported : getImports()) {
137 allDescriptors.addAll(imported.getAllDescriptors());
138 }
139 }
140 return allDescriptors;
141 }
142
143 @NotNull
144 private Map<LabelName, List<DeclarationDescriptor>> getLabelsToDescriptors() {
145 if (labelsToDescriptors == null) {
146 labelsToDescriptors = new HashMap<LabelName, List<DeclarationDescriptor>>();
147 }
148 return labelsToDescriptors;
149 }
150
151 @NotNull
152 private Map<Name, ClassDescriptor> getObjectDescriptorsMap() {
153 if (objectDescriptors == null) {
154 objectDescriptors = Maps.newHashMap();
155 }
156 return objectDescriptors;
157 }
158
159 @NotNull
160 @Override
161 public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
162 checkMayRead();
163
164 Collection<DeclarationDescriptor> superResult = super.getDeclarationsByLabel(labelName);
165 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors();
166 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(labelName);
167 if (declarationDescriptors == null) {
168 return superResult;
169 }
170 if (superResult.isEmpty()) return declarationDescriptors;
171 List<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>(declarationDescriptors);
172 result.addAll(superResult);
173 return result;
174 }
175
176 @Override
177 public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) {
178 checkMayWrite();
179
180 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors();
181 LabelName name = new LabelName(descriptor.getName().asString());
182 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(name);
183 if (declarationDescriptors == null) {
184 declarationDescriptors = new ArrayList<DeclarationDescriptor>();
185 labelsToDescriptors.put(name, declarationDescriptors);
186 }
187 declarationDescriptors.add(descriptor);
188 }
189
190 @NotNull
191 private Map<Name, DeclarationDescriptor> getVariableClassOrNamespaceDescriptors() {
192 if (variableClassOrNamespaceDescriptors == null) {
193 variableClassOrNamespaceDescriptors = Maps.newHashMap();
194 }
195 return variableClassOrNamespaceDescriptors;
196 }
197
198 @NotNull
199 private Map<Name, NamespaceDescriptor> getNamespaceAliases() {
200 if (namespaceAliases == null) {
201 namespaceAliases = Maps.newHashMap();
202 }
203 return namespaceAliases;
204 }
205
206 @Override
207 public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) {
208 addVariableDescriptor(variableDescriptor, false);
209 }
210
211 @Override
212 public void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor) {
213 addVariableDescriptor(propertyDescriptor, true);
214 }
215
216 private void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor, boolean isProperty) {
217 checkMayWrite();
218
219 Name name = variableDescriptor.getName();
220 if (isProperty) {
221 checkForPropertyRedeclaration(name, variableDescriptor);
222 getPropertyGroups().put(name, variableDescriptor);
223 }
224 if (variableDescriptor.getReceiverParameter() == null) {
225 checkForRedeclaration(name, variableDescriptor);
226 // TODO : Should this always happen?
227 getVariableClassOrNamespaceDescriptors().put(name, variableDescriptor);
228 }
229 allDescriptors.add(variableDescriptor);
230 addToDeclared(variableDescriptor);
231 }
232
233 @NotNull
234 @Override
235 public Set<VariableDescriptor> getProperties(@NotNull Name name) {
236 checkMayRead();
237
238 Set<VariableDescriptor> result = Sets.newLinkedHashSet(getPropertyGroups().get(name));
239
240 result.addAll(getWorkerScope().getProperties(name));
241
242 result.addAll(super.getProperties(name));
243
244 return result;
245 }
246
247 @Override
248 public VariableDescriptor getLocalVariable(@NotNull Name name) {
249 checkMayRead();
250
251 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
252 DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name);
253 if (descriptor instanceof VariableDescriptor && !getPropertyGroups().get(name).contains(descriptor)) {
254 return (VariableDescriptor) descriptor;
255 }
256
257 VariableDescriptor variableDescriptor = getWorkerScope().getLocalVariable(name);
258 if (variableDescriptor != null) {
259 return variableDescriptor;
260 }
261 return super.getLocalVariable(name);
262 }
263
264 @NotNull
265 private SetMultimap<Name, VariableDescriptor> getPropertyGroups() {
266 if (propertyGroups == null) {
267 propertyGroups = CommonSuppliers.newLinkedHashSetHashSetMultimap();
268 }
269 return propertyGroups;
270 }
271
272 @NotNull
273 private SetMultimap<Name, FunctionDescriptor> getFunctionGroups() {
274 if (functionGroups == null) {
275 functionGroups = CommonSuppliers.newLinkedHashSetHashSetMultimap();
276 }
277 return functionGroups;
278 }
279
280 @Override
281 public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) {
282 checkMayWrite();
283
284 getFunctionGroups().put(functionDescriptor.getName(), functionDescriptor);
285 allDescriptors.add(functionDescriptor);
286 }
287
288 @Override
289 @NotNull
290 public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
291 checkMayRead();
292
293 Set<FunctionDescriptor> result = Sets.newLinkedHashSet(getFunctionGroups().get(name));
294
295 result.addAll(getWorkerScope().getFunctions(name));
296
297 result.addAll(super.getFunctions(name));
298
299 return result;
300 }
301
302 @Override
303 public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
304 checkMayWrite();
305
306 Name name = typeParameterDescriptor.getName();
307 addClassifierAlias(name, typeParameterDescriptor);
308 }
309
310 @Override
311 public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) {
312 checkMayWrite();
313
314 if (isObject(classDescriptor)) {
315 throw new IllegalStateException("must not be object: " + classDescriptor);
316 }
317
318 addClassifierAlias(classDescriptor.getName(), classDescriptor);
319 }
320
321 @Override
322 public void addObjectDescriptor(@NotNull ClassDescriptor objectDescriptor) {
323 checkMayWrite();
324
325 if (!objectDescriptor.getKind().isObject()) {
326 throw new IllegalStateException("must be object: " + objectDescriptor);
327 }
328
329 getObjectDescriptorsMap().put(objectDescriptor.getName(), objectDescriptor);
330 }
331
332 @Override
333 public void addClassifierAlias(@NotNull Name name, @NotNull ClassifierDescriptor classifierDescriptor) {
334 checkMayWrite();
335
336 checkForRedeclaration(name, classifierDescriptor);
337 getVariableClassOrNamespaceDescriptors().put(name, classifierDescriptor);
338 allDescriptors.add(classifierDescriptor);
339 addToDeclared(classifierDescriptor);
340 }
341
342 @Override
343 public void addNamespaceAlias(@NotNull Name name, @NotNull NamespaceDescriptor namespaceDescriptor) {
344 checkMayWrite();
345
346 checkForRedeclaration(name, namespaceDescriptor);
347 getNamespaceAliases().put(name, namespaceDescriptor);
348 allDescriptors.add(namespaceDescriptor);
349 addToDeclared(namespaceDescriptor);
350 }
351
352 @Override
353 public void addFunctionAlias(@NotNull Name name, @NotNull FunctionDescriptor functionDescriptor) {
354 checkMayWrite();
355
356 checkForRedeclaration(name, functionDescriptor);
357 getFunctionGroups().put(name, functionDescriptor);
358 allDescriptors.add(functionDescriptor);
359 }
360
361 @Override
362 public void addVariableAlias(@NotNull Name name, @NotNull VariableDescriptor variableDescriptor) {
363 checkMayWrite();
364
365 checkForRedeclaration(name, variableDescriptor);
366 getVariableClassOrNamespaceDescriptors().put(name, variableDescriptor);
367 allDescriptors.add(variableDescriptor);
368 addToDeclared(variableDescriptor);
369 }
370
371 private void checkForPropertyRedeclaration(@NotNull Name name, VariableDescriptor variableDescriptor) {
372 Set<VariableDescriptor> properties = getPropertyGroups().get(name);
373 ReceiverParameterDescriptor receiverParameter = variableDescriptor.getReceiverParameter();
374 for (VariableDescriptor oldProperty : properties) {
375 ReceiverParameterDescriptor receiverParameterForOldVariable = oldProperty.getReceiverParameter();
376 if (((receiverParameter != null && receiverParameterForOldVariable != null) &&
377 (JetTypeChecker.INSTANCE.equalTypes(receiverParameter.getType(), receiverParameterForOldVariable.getType())))) {
378 redeclarationHandler.handleRedeclaration(oldProperty, variableDescriptor);
379 }
380 }
381 }
382
383 private void checkForRedeclaration(@NotNull Name name, DeclarationDescriptor classifierDescriptor) {
384 DeclarationDescriptor originalDescriptor = getVariableClassOrNamespaceDescriptors().get(name);
385 if (originalDescriptor != null) {
386 redeclarationHandler.handleRedeclaration(originalDescriptor, classifierDescriptor);
387 }
388 }
389
390 @Override
391 public ClassifierDescriptor getClassifier(@NotNull Name name) {
392 checkMayRead();
393
394 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
395 DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name);
396 if (descriptor instanceof ClassifierDescriptor) return (ClassifierDescriptor) descriptor;
397
398 ClassifierDescriptor classifierDescriptor = getWorkerScope().getClassifier(name);
399 if (classifierDescriptor != null) return classifierDescriptor;
400
401 return super.getClassifier(name);
402 }
403
404 @Override
405 public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
406 ClassDescriptor descriptor = getObjectDescriptorsMap().get(name);
407 if (descriptor != null) return descriptor;
408
409 ClassDescriptor fromWorker = getWorkerScope().getObjectDescriptor(name);
410 if (fromWorker != null) return fromWorker;
411
412 return super.getObjectDescriptor(name);
413 }
414
415 @NotNull
416 @Override
417 public Set<ClassDescriptor> getObjectDescriptors() {
418 if (allObjectDescriptors == null) {
419 allObjectDescriptors = Sets.newHashSet(getObjectDescriptorsMap().values());
420 allObjectDescriptors.addAll(getWorkerScope().getObjectDescriptors());
421 for (JetScope imported : getImports()) {
422 allObjectDescriptors.addAll(imported.getObjectDescriptors());
423 }
424 }
425 return allObjectDescriptors;
426 }
427
428 @Override
429 public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
430 checkMayWrite();
431
432 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
433 DeclarationDescriptor oldValue = variableClassOrNamespaceDescriptors.put(namespaceDescriptor.getName(), namespaceDescriptor);
434 if (oldValue != null) {
435 redeclarationHandler.handleRedeclaration(oldValue, namespaceDescriptor);
436 }
437 allDescriptors.add(namespaceDescriptor);
438 addToDeclared(namespaceDescriptor);
439 }
440
441 @Override
442 public NamespaceDescriptor getDeclaredNamespace(@NotNull Name name) {
443 checkMayRead();
444
445 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
446 DeclarationDescriptor namespaceDescriptor = variableClassOrNamespaceDescriptors.get(name);
447 if (namespaceDescriptor instanceof NamespaceDescriptor) return (NamespaceDescriptor) namespaceDescriptor;
448 return null;
449 }
450
451 @Override
452 public NamespaceDescriptor getNamespace(@NotNull Name name) {
453 checkMayRead();
454
455 NamespaceDescriptor declaredNamespace = getDeclaredNamespace(name);
456 if (declaredNamespace != null) return declaredNamespace;
457
458 NamespaceDescriptor aliased = getNamespaceAliases().get(name);
459 if (aliased != null) return aliased;
460
461 NamespaceDescriptor namespace = getWorkerScope().getNamespace(name);
462 if (namespace != null) return namespace;
463 return super.getNamespace(name);
464 }
465
466 @Override
467 public void setImplicitReceiver(@NotNull ReceiverParameterDescriptor implicitReceiver) {
468 checkMayWrite();
469
470 if (this.implicitReceiver != null) {
471 throw new UnsupportedOperationException("Receiver redeclared");
472 }
473 this.implicitReceiver = implicitReceiver;
474 }
475
476 @Override
477 protected List<ReceiverParameterDescriptor> computeImplicitReceiversHierarchy() {
478 List<ReceiverParameterDescriptor> implicitReceiverHierarchy = Lists.newArrayList();
479 if (implicitReceiver != null) {
480 implicitReceiverHierarchy.add(implicitReceiver);
481 }
482 implicitReceiverHierarchy.addAll(super.computeImplicitReceiversHierarchy());
483 return implicitReceiverHierarchy;
484 }
485
486 // @SuppressWarnings({"NullableProblems"})
487 @NotNull
488 private Map<Name, PropertyDescriptor> getPropertyDescriptorsByFieldNames() {
489 if (propertyDescriptorsByFieldNames == null) {
490 propertyDescriptorsByFieldNames = new HashMap<Name, PropertyDescriptor>();
491 }
492 return propertyDescriptorsByFieldNames;
493 }
494
495 @Override
496 public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) {
497 checkMayRead();
498
499 if (!fieldName.asString().startsWith("$")) {
500 throw new IllegalStateException();
501 }
502
503 PropertyDescriptor descriptor = getPropertyDescriptorsByFieldNames().get(fieldName);
504 if (descriptor != null) return descriptor;
505 return super.getPropertyByFieldReference(fieldName);
506 }
507
508 public List<VariableDescriptor> getDeclaredVariables() {
509 checkMayRead();
510
511 List<VariableDescriptor> result = Lists.newArrayList();
512 for (DeclarationDescriptor descriptor : getVariableClassOrNamespaceDescriptors().values()) {
513 if (descriptor instanceof VariableDescriptor) {
514 VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
515 result.add(variableDescriptor);
516 }
517 }
518 return result;
519 }
520
521 public boolean hasDeclaredItems() {
522 return variableClassOrNamespaceDescriptors != null && !variableClassOrNamespaceDescriptors.isEmpty();
523 }
524
525 private void addToDeclared(DeclarationDescriptor descriptor) {
526 declaredDescriptorsAccessibleBySimpleName.put(descriptor.getName(), descriptor);
527 }
528
529 @NotNull
530 @Override
531 public Multimap<Name, DeclarationDescriptor> getDeclaredDescriptorsAccessibleBySimpleName() {
532 return declaredDescriptorsAccessibleBySimpleName;
533 }
534
535 @NotNull
536 @Override
537 public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
538 return declaredDescriptorsAccessibleBySimpleName.values();
539 }
540
541 private static boolean isObject(@NotNull ClassifierDescriptor classifier) {
542 if (classifier instanceof ClassDescriptor) {
543 ClassDescriptor clazz = (ClassDescriptor) classifier;
544 return clazz.getKind().isObject();
545 }
546 else if (classifier instanceof TypeParameterDescriptor) {
547 return false;
548 }
549 else {
550 throw new IllegalStateException("unknown classifier: " + classifier);
551 }
552 }
553 }