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 }