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