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.INSTANCE.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    }