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