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.Printer;
028
029 import java.util.*;
030
031 // Reads from:
032 // 1. Maps
033 // 2. Worker
034 // 3. Imports
035
036 // Writes to: maps
037
038 public class WritableScopeImpl extends WritableScopeWithImports {
039
040 private final Collection<DeclarationDescriptor> allDescriptors = Lists.newArrayList();
041 private final Multimap<Name, DeclarationDescriptor> declaredDescriptorsAccessibleBySimpleName = HashMultimap.create();
042 private boolean allDescriptorsDone = false;
043
044 @NotNull
045 private final DeclarationDescriptor ownerDeclarationDescriptor;
046
047 @Nullable
048 private SetMultimap<Name, FunctionDescriptor> functionGroups;
049
050 @Nullable
051 private Map<Name, DeclarationDescriptor> variableOrClassDescriptors;
052
053 @Nullable
054 private SetMultimap<Name, VariableDescriptor> propertyGroups;
055
056 @Nullable
057 private Map<Name, PackageViewDescriptor> packageAliases;
058
059 @Nullable
060 private Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors;
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 importPackageAlias(@NotNull Name aliasName, @NotNull PackageViewDescriptor packageView) {
093 checkMayWrite();
094
095 allDescriptors.add(packageView);
096 super.importPackageAlias(aliasName, packageView);
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 @Override
152 public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
153 checkMayRead();
154
155 Collection<DeclarationDescriptor> superResult = super.getDeclarationsByLabel(labelName);
156 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors();
157 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(labelName);
158 if (declarationDescriptors == null) {
159 return superResult;
160 }
161 if (superResult.isEmpty()) return declarationDescriptors;
162 List<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>(declarationDescriptors);
163 result.addAll(superResult);
164 return result;
165 }
166
167 @Override
168 public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) {
169 checkMayWrite();
170
171 Map<LabelName, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors();
172 LabelName name = new LabelName(descriptor.getName().asString());
173 List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(name);
174 if (declarationDescriptors == null) {
175 declarationDescriptors = new ArrayList<DeclarationDescriptor>();
176 labelsToDescriptors.put(name, declarationDescriptors);
177 }
178 declarationDescriptors.add(descriptor);
179 }
180
181 @NotNull
182 private Map<Name, DeclarationDescriptor> getVariableOrClassDescriptors() {
183 if (variableOrClassDescriptors == null) {
184 variableOrClassDescriptors = Maps.newHashMap();
185 }
186 return variableOrClassDescriptors;
187 }
188
189 @NotNull
190 private Map<Name, PackageViewDescriptor> getPackageAliases() {
191 if (packageAliases == null) {
192 packageAliases = Maps.newHashMap();
193 }
194 return packageAliases;
195 }
196
197 @Override
198 public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) {
199 addVariableDescriptor(variableDescriptor, false);
200 }
201
202 @Override
203 public void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor) {
204 addVariableDescriptor(propertyDescriptor, true);
205 }
206
207 private void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor, boolean isProperty) {
208 checkMayWrite();
209
210 Name name = variableDescriptor.getName();
211 if (isProperty) {
212 checkForPropertyRedeclaration(name, variableDescriptor);
213 getPropertyGroups().put(name, variableDescriptor);
214 }
215 if (variableDescriptor.getReceiverParameter() == null) {
216 checkForRedeclaration(name, variableDescriptor);
217 // TODO : Should this always happen?
218 getVariableOrClassDescriptors().put(name, variableDescriptor);
219 }
220 allDescriptors.add(variableDescriptor);
221 addToDeclared(variableDescriptor);
222 }
223
224 @NotNull
225 @Override
226 public Set<VariableDescriptor> getProperties(@NotNull Name name) {
227 checkMayRead();
228
229 Set<VariableDescriptor> result = Sets.newLinkedHashSet(getPropertyGroups().get(name));
230
231 result.addAll(getWorkerScope().getProperties(name));
232
233 result.addAll(super.getProperties(name));
234
235 return result;
236 }
237
238 @Override
239 public VariableDescriptor getLocalVariable(@NotNull Name name) {
240 checkMayRead();
241
242 Map<Name, DeclarationDescriptor> variableOrClassDescriptors = getVariableOrClassDescriptors();
243 DeclarationDescriptor descriptor = variableOrClassDescriptors.get(name);
244 if (descriptor instanceof VariableDescriptor && !getPropertyGroups().get(name).contains(descriptor)) {
245 return (VariableDescriptor) descriptor;
246 }
247
248 VariableDescriptor variableDescriptor = getWorkerScope().getLocalVariable(name);
249 if (variableDescriptor != null) {
250 return variableDescriptor;
251 }
252 return super.getLocalVariable(name);
253 }
254
255 @NotNull
256 private SetMultimap<Name, VariableDescriptor> getPropertyGroups() {
257 if (propertyGroups == null) {
258 propertyGroups = LinkedHashMultimap.create();
259 }
260 return propertyGroups;
261 }
262
263 @NotNull
264 private SetMultimap<Name, FunctionDescriptor> getFunctionGroups() {
265 if (functionGroups == null) {
266 functionGroups = LinkedHashMultimap.create();
267 }
268 return functionGroups;
269 }
270
271 @Override
272 public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) {
273 checkMayWrite();
274
275 getFunctionGroups().put(functionDescriptor.getName(), functionDescriptor);
276 allDescriptors.add(functionDescriptor);
277 }
278
279 @Override
280 @NotNull
281 public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
282 checkMayRead();
283
284 Set<FunctionDescriptor> result = Sets.newLinkedHashSet(getFunctionGroups().get(name));
285
286 result.addAll(getWorkerScope().getFunctions(name));
287
288 result.addAll(super.getFunctions(name));
289
290 return result;
291 }
292
293 @Override
294 public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
295 checkMayWrite();
296
297 Name name = typeParameterDescriptor.getName();
298 addClassifierAlias(name, typeParameterDescriptor);
299 }
300
301 @Override
302 public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) {
303 checkMayWrite();
304
305 addClassifierAlias(classDescriptor.getName(), classDescriptor);
306 }
307
308 @Override
309 public void addClassifierAlias(@NotNull Name name, @NotNull ClassifierDescriptor classifierDescriptor) {
310 checkMayWrite();
311
312 checkForRedeclaration(name, classifierDescriptor);
313 getVariableOrClassDescriptors().put(name, classifierDescriptor);
314 allDescriptors.add(classifierDescriptor);
315 addToDeclared(classifierDescriptor);
316 }
317
318 @Override
319 public void addPackageAlias(@NotNull Name name, @NotNull PackageViewDescriptor packageView) {
320 checkMayWrite();
321
322 checkForRedeclaration(name, packageView);
323 getPackageAliases().put(name, packageView);
324 allDescriptors.add(packageView);
325 addToDeclared(packageView);
326 }
327
328 @Override
329 public void addFunctionAlias(@NotNull Name name, @NotNull FunctionDescriptor functionDescriptor) {
330 checkMayWrite();
331
332 checkForRedeclaration(name, functionDescriptor);
333 getFunctionGroups().put(name, functionDescriptor);
334 allDescriptors.add(functionDescriptor);
335 }
336
337 @Override
338 public void addVariableAlias(@NotNull Name name, @NotNull VariableDescriptor variableDescriptor) {
339 checkMayWrite();
340
341 checkForRedeclaration(name, variableDescriptor);
342
343 getVariableOrClassDescriptors().put(name, variableDescriptor);
344 getPropertyGroups().put(name, variableDescriptor);
345
346 allDescriptors.add(variableDescriptor);
347 addToDeclared(variableDescriptor);
348 }
349
350 private void checkForPropertyRedeclaration(@NotNull Name name, VariableDescriptor variableDescriptor) {
351 Set<VariableDescriptor> properties = getPropertyGroups().get(name);
352 ReceiverParameterDescriptor receiverParameter = variableDescriptor.getReceiverParameter();
353 for (VariableDescriptor oldProperty : properties) {
354 ReceiverParameterDescriptor receiverParameterForOldVariable = oldProperty.getReceiverParameter();
355 if (((receiverParameter != null && receiverParameterForOldVariable != null) &&
356 (JetTypeChecker.INSTANCE.equalTypes(receiverParameter.getType(), receiverParameterForOldVariable.getType())))) {
357 redeclarationHandler.handleRedeclaration(oldProperty, variableDescriptor);
358 }
359 }
360 }
361
362 private void checkForRedeclaration(@NotNull Name name, DeclarationDescriptor classifierDescriptor) {
363 DeclarationDescriptor originalDescriptor = getVariableOrClassDescriptors().get(name);
364 if (originalDescriptor != null) {
365 redeclarationHandler.handleRedeclaration(originalDescriptor, classifierDescriptor);
366 }
367 }
368
369 @Override
370 public ClassifierDescriptor getClassifier(@NotNull Name name) {
371 checkMayRead();
372
373 Map<Name, DeclarationDescriptor> variableOrClassDescriptors = getVariableOrClassDescriptors();
374 DeclarationDescriptor descriptor = variableOrClassDescriptors.get(name);
375 if (descriptor instanceof ClassifierDescriptor) return (ClassifierDescriptor) descriptor;
376
377 ClassifierDescriptor classifierDescriptor = getWorkerScope().getClassifier(name);
378 if (classifierDescriptor != null) return classifierDescriptor;
379
380 return super.getClassifier(name);
381 }
382
383 @Override
384 public PackageViewDescriptor getPackage(@NotNull Name name) {
385 checkMayRead();
386
387 PackageViewDescriptor aliased = getPackageAliases().get(name);
388 if (aliased != null) return aliased;
389
390 PackageViewDescriptor packageView = getWorkerScope().getPackage(name);
391 if (packageView != null) return packageView;
392 return super.getPackage(name);
393 }
394
395 @Override
396 public void setImplicitReceiver(@NotNull ReceiverParameterDescriptor implicitReceiver) {
397 checkMayWrite();
398
399 if (this.implicitReceiver != null) {
400 throw new UnsupportedOperationException("Receiver redeclared");
401 }
402 this.implicitReceiver = implicitReceiver;
403 }
404
405 @Override
406 protected List<ReceiverParameterDescriptor> computeImplicitReceiversHierarchy() {
407 List<ReceiverParameterDescriptor> implicitReceiverHierarchy = Lists.newArrayList();
408 if (implicitReceiver != null) {
409 implicitReceiverHierarchy.add(implicitReceiver);
410 }
411 implicitReceiverHierarchy.addAll(super.computeImplicitReceiversHierarchy());
412 return implicitReceiverHierarchy;
413 }
414
415 private void addToDeclared(DeclarationDescriptor descriptor) {
416 declaredDescriptorsAccessibleBySimpleName.put(descriptor.getName(), descriptor);
417 }
418
419 @NotNull
420 @Override
421 public Multimap<Name, DeclarationDescriptor> getDeclaredDescriptorsAccessibleBySimpleName() {
422 return declaredDescriptorsAccessibleBySimpleName;
423 }
424
425 @NotNull
426 @Override
427 public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
428 return declaredDescriptorsAccessibleBySimpleName.values();
429 }
430
431 @TestOnly
432 @Override
433 protected void printAdditionalScopeStructure(@NotNull Printer p) {
434 p.println("allDescriptorsDone = ", allDescriptorsDone);
435 }
436 }