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