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