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.Lists;
020    import com.google.common.collect.Sets;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.resolve.name.Name;
025    
026    import java.util.*;
027    
028    public abstract class WritableScopeWithImports extends JetScopeAdapter implements WritableScope {
029    
030        @NotNull
031        private final String debugName;
032    
033        @Nullable
034        private List<JetScope> imports;
035        private WritableScope currentIndividualImportScope;
036        protected final RedeclarationHandler redeclarationHandler;
037        private List<ReceiverParameterDescriptor> implicitReceiverHierarchy;
038    
039        public WritableScopeWithImports(@NotNull JetScope scope, @NotNull RedeclarationHandler redeclarationHandler, @NotNull String debugName) {
040            super(scope);
041            this.redeclarationHandler = redeclarationHandler;
042            this.debugName = debugName;
043        }
044    
045    
046    
047        private LockLevel lockLevel = LockLevel.WRITING;
048    
049        @Override
050        public WritableScope changeLockLevel(LockLevel lockLevel) {
051            if (lockLevel.ordinal() < this.lockLevel.ordinal()) {
052                throw new IllegalStateException("cannot lower lock level from " + this.lockLevel + " to " + lockLevel + " at " + toString());
053            }
054            this.lockLevel = lockLevel;
055            return this;
056        }
057    
058        protected void checkMayRead() {
059            if (lockLevel != LockLevel.READING && lockLevel != LockLevel.BOTH) {
060                throw new IllegalStateException("cannot read with lock level " + lockLevel + " at " + toString());
061            }
062        }
063    
064        protected void checkMayWrite() {
065            if (lockLevel != LockLevel.WRITING && lockLevel != LockLevel.BOTH) {
066                throw new IllegalStateException("cannot write with lock level " + lockLevel + " at " + toString());
067            }
068        }
069        
070        protected void checkMayNotWrite() {
071            if (lockLevel == LockLevel.WRITING || lockLevel == LockLevel.BOTH) {
072                throw new IllegalStateException("cannot write with lock level " + lockLevel + " at " + toString());
073            }
074        }
075    
076    
077    
078    
079        @NotNull
080        protected final List<JetScope> getImports() {
081            if (imports == null) {
082                imports = new ArrayList<JetScope>();
083            }
084            return imports;
085        }
086    
087        @Override
088        public void importScope(@NotNull JetScope imported) {
089            if (imported == this) {
090                throw new IllegalStateException("cannot import scope into self");
091            }
092    
093            checkMayWrite();
094    
095            getImports().add(0, imported);
096            currentIndividualImportScope = null;
097        }
098    
099        @NotNull
100        @Override
101        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
102            checkMayRead();
103    
104            if (implicitReceiverHierarchy == null) {
105                implicitReceiverHierarchy = computeImplicitReceiversHierarchy();
106            }
107            return implicitReceiverHierarchy;
108        }
109    
110        protected List<ReceiverParameterDescriptor> computeImplicitReceiversHierarchy() {
111            List<ReceiverParameterDescriptor> implicitReceiverHierarchy = Lists.newArrayList();
112            // Imported scopes come with their receivers
113            // Example: class member resolution scope imports a scope of it's class object
114            //          members of the class object must be able to find it as an implicit receiver
115            for (JetScope scope : getImports()) {
116                implicitReceiverHierarchy.addAll(scope.getImplicitReceiversHierarchy());
117            }
118            implicitReceiverHierarchy.addAll(super.getImplicitReceiversHierarchy());
119            return implicitReceiverHierarchy;
120        }
121    
122        @NotNull
123        @Override
124        public Set<VariableDescriptor> getProperties(@NotNull Name name) {
125            checkMayRead();
126    
127            Set<VariableDescriptor> properties = Sets.newLinkedHashSet();
128            for (JetScope imported : getImports()) {
129                properties.addAll(imported.getProperties(name));
130            }
131            return properties;
132        }
133    
134        @Override
135        public VariableDescriptor getLocalVariable(@NotNull Name name) {
136            checkMayRead();
137    
138            // Meaningful lookup goes here
139            for (JetScope imported : getImports()) {
140                VariableDescriptor importedDescriptor = imported.getLocalVariable(name);
141                if (importedDescriptor != null) {
142                    return importedDescriptor;
143                }
144            }
145            return null;
146        }
147    
148        @NotNull
149        @Override
150        public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
151            checkMayRead();
152    
153            if (getImports().isEmpty()) {
154                return Collections.emptySet();
155            }
156            Set<FunctionDescriptor> result = Sets.newLinkedHashSet();
157            for (JetScope imported : getImports()) {
158                result.addAll(imported.getFunctions(name));
159            }
160            return result;
161        }
162    
163        @Override
164        public ClassifierDescriptor getClassifier(@NotNull Name name) {
165            checkMayRead();
166    
167            for (JetScope imported : getImports()) {
168                ClassifierDescriptor importedClassifier = imported.getClassifier(name);
169                if (importedClassifier != null) {
170                    return importedClassifier;
171                }
172            }
173            return null;
174        }
175    
176        @Override
177        public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
178            checkMayRead();
179    
180            for (JetScope imported : getImports()) {
181                ClassDescriptor objectDescriptor = imported.getObjectDescriptor(name);
182                if (objectDescriptor != null) {
183                    return objectDescriptor;
184                }
185            }
186            return null;
187        }
188    
189        @Override
190        public NamespaceDescriptor getNamespace(@NotNull Name name) {
191            checkMayRead();
192    
193            for (JetScope imported : getImports()) {
194                NamespaceDescriptor importedDescriptor = imported.getNamespace(name);
195                if (importedDescriptor != null) {
196                    return importedDescriptor;
197                }
198            }
199            return null;
200        }
201    
202        private WritableScope getCurrentIndividualImportScope() {
203            if (currentIndividualImportScope == null) {
204                WritableScopeImpl writableScope = new WritableScopeImpl(EMPTY, getContainingDeclaration(), RedeclarationHandler.DO_NOTHING, "Individual import scope");
205                writableScope.changeLockLevel(LockLevel.BOTH);
206                importScope(writableScope);
207                currentIndividualImportScope = writableScope;
208            }
209            return currentIndividualImportScope;
210        }
211    
212        @Override
213        public void importClassifierAlias(@NotNull Name importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) {
214            checkMayWrite();
215    
216            getCurrentIndividualImportScope().addClassifierAlias(importedClassifierName, classifierDescriptor);
217        }
218        
219        
220        @Override
221        public void importNamespaceAlias(@NotNull Name aliasName, @NotNull NamespaceDescriptor namespaceDescriptor) {
222            checkMayWrite();
223    
224            getCurrentIndividualImportScope().addNamespaceAlias(aliasName, namespaceDescriptor);
225        }
226    
227        @Override
228        public void importFunctionAlias(@NotNull Name aliasName, @NotNull FunctionDescriptor functionDescriptor) {
229            checkMayWrite();
230    
231            getCurrentIndividualImportScope().addFunctionAlias(aliasName, functionDescriptor);
232        }
233    
234        @Override
235        public void importVariableAlias(@NotNull Name aliasName, @NotNull VariableDescriptor variableDescriptor) {
236            checkMayWrite();
237    
238            getCurrentIndividualImportScope().addVariableAlias(aliasName, variableDescriptor);
239        }
240    
241        @Override
242        public void clearImports() {
243            currentIndividualImportScope = null;
244            getImports().clear();
245        }
246    
247        @Override
248        public String toString() {
249            return getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + " " + debugName + " for " + getContainingDeclaration();
250        }
251    
252    }