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