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.utils.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 @Nullable
042 private SetMultimap<Name, FunctionDescriptor> functionGroups;
043
044 @Nullable
045 private Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors;
046
047 @Nullable
048 private SetMultimap<Name, VariableDescriptor> propertyGroups;
049
050 @Nullable
051 private Map<Name, NamespaceDescriptor> namespaceAliases;
052
053 @Nullable
054 private Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors;
055
056 @Nullable
057 private Map<Name, ClassDescriptor> objectDescriptors;
058
059 @Nullable
060 private ReceiverParameterDescriptor implicitReceiver;
061
062 public WritableScopeImpl(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner,
063 @NotNull RedeclarationHandler redeclarationHandler, @NotNull String debugName) {
064 super(scope, redeclarationHandler, debugName);
065 this.ownerDeclarationDescriptor = owner;
066 }
067
068 @NotNull
069 @Override
070 public DeclarationDescriptor getContainingDeclaration() {
071 return ownerDeclarationDescriptor;
072 }
073
074 @Override
075 public void importScope(@NotNull JetScope imported) {
076 checkMayWrite();
077 super.importScope(imported);
078 }
079
080 @Override
081 public void importClassifierAlias(@NotNull Name importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) {
082 checkMayWrite();
083
084 allDescriptors.add(classifierDescriptor);
085 super.importClassifierAlias(importedClassifierName, classifierDescriptor);
086 }
087
088 @Override
089 public void importNamespaceAlias(@NotNull Name aliasName, @NotNull NamespaceDescriptor namespaceDescriptor) {
090 checkMayWrite();
091
092 allDescriptors.add(namespaceDescriptor);
093 super.importNamespaceAlias(aliasName, namespaceDescriptor);
094 }
095
096 @Override
097 public void importFunctionAlias(@NotNull Name aliasName, @NotNull FunctionDescriptor functionDescriptor) {
098 checkMayWrite();
099
100 addFunctionDescriptor(functionDescriptor);
101 super.importFunctionAlias(aliasName, functionDescriptor);
102
103 }
104
105 @Override
106 public void importVariableAlias(@NotNull Name aliasName, @NotNull VariableDescriptor variableDescriptor) {
107 checkMayWrite();
108
109 addPropertyDescriptor(variableDescriptor);
110 super.importVariableAlias(aliasName, variableDescriptor);
111 }
112
113 @Override
114 public void clearImports() {
115 checkMayWrite();
116
117 super.clearImports();
118 }
119
120 @NotNull
121 @Override
122 public Collection<DeclarationDescriptor> getAllDescriptors() {
123 checkMayRead();
124
125 if (!allDescriptorsDone) {
126 allDescriptorsDone = true;
127
128 // make sure no descriptors added to allDescriptors collection
129 changeLockLevel(LockLevel.READING);
130
131 allDescriptors.addAll(getWorkerScope().getAllDescriptors());
132 for (JetScope imported : getImports()) {
133 allDescriptors.addAll(imported.getAllDescriptors());
134 }
135 }
136 return allDescriptors;
137 }
138
139 @NotNull
140 private Map<LabelName, List<DeclarationDescriptor>> getLabelsToDescriptors() {
141 if (labelsToDescriptors == null) {
142 labelsToDescriptors = new HashMap<LabelName, List<DeclarationDescriptor>>();
143 }
144 return labelsToDescriptors;
145 }
146
147 @NotNull
148 private Map<Name, ClassDescriptor> getObjectDescriptorsMap() {
149 if (objectDescriptors == null) {
150 objectDescriptors = Maps.newHashMap();
151 }
152 return objectDescriptors;
153 }
154
155 @NotNull
156 @Override
157 public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
158 checkMayRead();
159
160 Collection<DeclarationDescriptor> superResult = super.getDeclarationsByLabel(labelName);
161 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors();
162 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(labelName);
163 if (declarationDescriptors == null) {
164 return superResult;
165 }
166 if (superResult.isEmpty()) return declarationDescriptors;
167 List<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>(declarationDescriptors);
168 result.addAll(superResult);
169 return result;
170 }
171
172 @Override
173 public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) {
174 checkMayWrite();
175
176 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors();
177 LabelName name = new LabelName(descriptor.getName().asString());
178 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(name);
179 if (declarationDescriptors == null) {
180 declarationDescriptors = new ArrayList<DeclarationDescriptor>();
181 labelsToDescriptors.put(name, declarationDescriptors);
182 }
183 declarationDescriptors.add(descriptor);
184 }
185
186 @NotNull
187 private Map<Name, DeclarationDescriptor> getVariableClassOrNamespaceDescriptors() {
188 if (variableClassOrNamespaceDescriptors == null) {
189 variableClassOrNamespaceDescriptors = Maps.newHashMap();
190 }
191 return variableClassOrNamespaceDescriptors;
192 }
193
194 @NotNull
195 private Map<Name, NamespaceDescriptor> getNamespaceAliases() {
196 if (namespaceAliases == null) {
197 namespaceAliases = Maps.newHashMap();
198 }
199 return namespaceAliases;
200 }
201
202 @Override
203 public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) {
204 addVariableDescriptor(variableDescriptor, false);
205 }
206
207 @Override
208 public void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor) {
209 addVariableDescriptor(propertyDescriptor, true);
210 }
211
212 private void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor, boolean isProperty) {
213 checkMayWrite();
214
215 Name name = variableDescriptor.getName();
216 if (isProperty) {
217 checkForPropertyRedeclaration(name, variableDescriptor);
218 getPropertyGroups().put(name, variableDescriptor);
219 }
220 if (variableDescriptor.getReceiverParameter() == null) {
221 checkForRedeclaration(name, variableDescriptor);
222 // TODO : Should this always happen?
223 getVariableClassOrNamespaceDescriptors().put(name, variableDescriptor);
224 }
225 allDescriptors.add(variableDescriptor);
226 addToDeclared(variableDescriptor);
227 }
228
229 @NotNull
230 @Override
231 public Set<VariableDescriptor> getProperties(@NotNull Name name) {
232 checkMayRead();
233
234 Set<VariableDescriptor> result = Sets.newLinkedHashSet(getPropertyGroups().get(name));
235
236 result.addAll(getWorkerScope().getProperties(name));
237
238 result.addAll(super.getProperties(name));
239
240 return result;
241 }
242
243 @Override
244 public VariableDescriptor getLocalVariable(@NotNull Name name) {
245 checkMayRead();
246
247 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
248 DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name);
249 if (descriptor instanceof VariableDescriptor && !getPropertyGroups().get(name).contains(descriptor)) {
250 return (VariableDescriptor) descriptor;
251 }
252
253 VariableDescriptor variableDescriptor = getWorkerScope().getLocalVariable(name);
254 if (variableDescriptor != null) {
255 return variableDescriptor;
256 }
257 return super.getLocalVariable(name);
258 }
259
260 @NotNull
261 private SetMultimap<Name, VariableDescriptor> getPropertyGroups() {
262 if (propertyGroups == null) {
263 propertyGroups = CommonSuppliers.newLinkedHashSetHashSetMultimap();
264 }
265 return propertyGroups;
266 }
267
268 @NotNull
269 private SetMultimap<Name, FunctionDescriptor> getFunctionGroups() {
270 if (functionGroups == null) {
271 functionGroups = CommonSuppliers.newLinkedHashSetHashSetMultimap();
272 }
273 return functionGroups;
274 }
275
276 @Override
277 public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) {
278 checkMayWrite();
279
280 getFunctionGroups().put(functionDescriptor.getName(), functionDescriptor);
281 allDescriptors.add(functionDescriptor);
282 }
283
284 @Override
285 @NotNull
286 public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
287 checkMayRead();
288
289 Set<FunctionDescriptor> result = Sets.newLinkedHashSet(getFunctionGroups().get(name));
290
291 result.addAll(getWorkerScope().getFunctions(name));
292
293 result.addAll(super.getFunctions(name));
294
295 return result;
296 }
297
298 @Override
299 public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
300 checkMayWrite();
301
302 Name name = typeParameterDescriptor.getName();
303 addClassifierAlias(name, typeParameterDescriptor);
304 }
305
306 @Override
307 public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) {
308 checkMayWrite();
309
310 if (isObject(classDescriptor)) {
311 throw new IllegalStateException("must not be object: " + classDescriptor);
312 }
313
314 addClassifierAlias(classDescriptor.getName(), classDescriptor);
315 }
316
317 @Override
318 public void addObjectDescriptor(@NotNull ClassDescriptor objectDescriptor) {
319 checkMayWrite();
320
321 if (!objectDescriptor.getKind().isObject()) {
322 throw new IllegalStateException("must be object: " + objectDescriptor);
323 }
324
325 getObjectDescriptorsMap().put(objectDescriptor.getName(), objectDescriptor);
326 }
327
328 @Override
329 public void addClassifierAlias(@NotNull Name name, @NotNull ClassifierDescriptor classifierDescriptor) {
330 checkMayWrite();
331
332 checkForRedeclaration(name, classifierDescriptor);
333 getVariableClassOrNamespaceDescriptors().put(name, classifierDescriptor);
334 allDescriptors.add(classifierDescriptor);
335 addToDeclared(classifierDescriptor);
336 }
337
338 @Override
339 public void addNamespaceAlias(@NotNull Name name, @NotNull NamespaceDescriptor namespaceDescriptor) {
340 checkMayWrite();
341
342 checkForRedeclaration(name, namespaceDescriptor);
343 getNamespaceAliases().put(name, namespaceDescriptor);
344 allDescriptors.add(namespaceDescriptor);
345 addToDeclared(namespaceDescriptor);
346 }
347
348 @Override
349 public void addFunctionAlias(@NotNull Name name, @NotNull FunctionDescriptor functionDescriptor) {
350 checkMayWrite();
351
352 checkForRedeclaration(name, functionDescriptor);
353 getFunctionGroups().put(name, functionDescriptor);
354 allDescriptors.add(functionDescriptor);
355 }
356
357 @Override
358 public void addVariableAlias(@NotNull Name name, @NotNull VariableDescriptor variableDescriptor) {
359 checkMayWrite();
360
361 checkForRedeclaration(name, variableDescriptor);
362 getVariableClassOrNamespaceDescriptors().put(name, variableDescriptor);
363 allDescriptors.add(variableDescriptor);
364 addToDeclared(variableDescriptor);
365 }
366
367 private void checkForPropertyRedeclaration(@NotNull Name name, VariableDescriptor variableDescriptor) {
368 Set<VariableDescriptor> properties = getPropertyGroups().get(name);
369 ReceiverParameterDescriptor receiverParameter = variableDescriptor.getReceiverParameter();
370 for (VariableDescriptor oldProperty : properties) {
371 ReceiverParameterDescriptor receiverParameterForOldVariable = oldProperty.getReceiverParameter();
372 if (((receiverParameter != null && receiverParameterForOldVariable != null) &&
373 (JetTypeChecker.INSTANCE.equalTypes(receiverParameter.getType(), receiverParameterForOldVariable.getType())))) {
374 redeclarationHandler.handleRedeclaration(oldProperty, variableDescriptor);
375 }
376 }
377 }
378
379 private void checkForRedeclaration(@NotNull Name name, DeclarationDescriptor classifierDescriptor) {
380 DeclarationDescriptor originalDescriptor = getVariableClassOrNamespaceDescriptors().get(name);
381 if (originalDescriptor != null) {
382 redeclarationHandler.handleRedeclaration(originalDescriptor, classifierDescriptor);
383 }
384 }
385
386 @Override
387 public ClassifierDescriptor getClassifier(@NotNull Name name) {
388 checkMayRead();
389
390 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
391 DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name);
392 if (descriptor instanceof ClassifierDescriptor) return (ClassifierDescriptor) descriptor;
393
394 ClassifierDescriptor classifierDescriptor = getWorkerScope().getClassifier(name);
395 if (classifierDescriptor != null) return classifierDescriptor;
396
397 return super.getClassifier(name);
398 }
399
400 @Override
401 public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
402 ClassDescriptor descriptor = getObjectDescriptorsMap().get(name);
403 if (descriptor != null) return descriptor;
404
405 ClassDescriptor fromWorker = getWorkerScope().getObjectDescriptor(name);
406 if (fromWorker != null) return fromWorker;
407
408 return super.getObjectDescriptor(name);
409 }
410
411 @NotNull
412 @Override
413 public Set<ClassDescriptor> getObjectDescriptors() {
414 if (allObjectDescriptors == null) {
415 allObjectDescriptors = Sets.newHashSet(getObjectDescriptorsMap().values());
416 allObjectDescriptors.addAll(getWorkerScope().getObjectDescriptors());
417 for (JetScope imported : getImports()) {
418 allObjectDescriptors.addAll(imported.getObjectDescriptors());
419 }
420 }
421 return allObjectDescriptors;
422 }
423
424 @Override
425 public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
426 checkMayWrite();
427
428 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
429 DeclarationDescriptor oldValue = variableClassOrNamespaceDescriptors.put(namespaceDescriptor.getName(), namespaceDescriptor);
430 if (oldValue != null) {
431 redeclarationHandler.handleRedeclaration(oldValue, namespaceDescriptor);
432 }
433 allDescriptors.add(namespaceDescriptor);
434 addToDeclared(namespaceDescriptor);
435 }
436
437 @Override
438 public NamespaceDescriptor getDeclaredNamespace(@NotNull Name name) {
439 checkMayRead();
440
441 Map<Name, DeclarationDescriptor> variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors();
442 DeclarationDescriptor namespaceDescriptor = variableClassOrNamespaceDescriptors.get(name);
443 if (namespaceDescriptor instanceof NamespaceDescriptor) return (NamespaceDescriptor) namespaceDescriptor;
444 return null;
445 }
446
447 @Override
448 public NamespaceDescriptor getNamespace(@NotNull Name name) {
449 checkMayRead();
450
451 NamespaceDescriptor declaredNamespace = getDeclaredNamespace(name);
452 if (declaredNamespace != null) return declaredNamespace;
453
454 NamespaceDescriptor aliased = getNamespaceAliases().get(name);
455 if (aliased != null) return aliased;
456
457 NamespaceDescriptor namespace = getWorkerScope().getNamespace(name);
458 if (namespace != null) return namespace;
459 return super.getNamespace(name);
460 }
461
462 @Override
463 public void setImplicitReceiver(@NotNull ReceiverParameterDescriptor implicitReceiver) {
464 checkMayWrite();
465
466 if (this.implicitReceiver != null) {
467 throw new UnsupportedOperationException("Receiver redeclared");
468 }
469 this.implicitReceiver = implicitReceiver;
470 }
471
472 @Override
473 protected List<ReceiverParameterDescriptor> computeImplicitReceiversHierarchy() {
474 List<ReceiverParameterDescriptor> implicitReceiverHierarchy = Lists.newArrayList();
475 if (implicitReceiver != null) {
476 implicitReceiverHierarchy.add(implicitReceiver);
477 }
478 implicitReceiverHierarchy.addAll(super.computeImplicitReceiversHierarchy());
479 return implicitReceiverHierarchy;
480 }
481
482 private void addToDeclared(DeclarationDescriptor descriptor) {
483 declaredDescriptorsAccessibleBySimpleName.put(descriptor.getName(), descriptor);
484 }
485
486 @NotNull
487 @Override
488 public Multimap<Name, DeclarationDescriptor> getDeclaredDescriptorsAccessibleBySimpleName() {
489 return declaredDescriptorsAccessibleBySimpleName;
490 }
491
492 @NotNull
493 @Override
494 public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
495 return declaredDescriptorsAccessibleBySimpleName.values();
496 }
497
498 private static boolean isObject(@NotNull ClassifierDescriptor classifier) {
499 if (classifier instanceof ClassDescriptor) {
500 ClassDescriptor clazz = (ClassDescriptor) classifier;
501 return clazz.getKind().isObject();
502 }
503 else if (classifier instanceof TypeParameterDescriptor) {
504 return false;
505 }
506 else {
507 throw new IllegalStateException("unknown classifier: " + classifier);
508 }
509 }
510 }