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