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 017package org.jetbrains.jet.lang.resolve.scopes; 018 019import com.google.common.collect.Lists; 020import com.google.common.collect.Sets; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.resolve.name.Name; 025 026import java.util.*; 027 028public 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}