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