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