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