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    }