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.lazy; 018 019import com.google.common.collect.Lists; 020import com.google.common.collect.Maps; 021import com.google.common.collect.Sets; 022import org.jetbrains.annotations.NotNull; 023import org.jetbrains.annotations.Nullable; 024import org.jetbrains.jet.lang.descriptors.*; 025import org.jetbrains.jet.lang.psi.JetFile; 026import org.jetbrains.jet.lang.psi.JetImportDirective; 027import org.jetbrains.jet.lang.resolve.BindingTrace; 028import org.jetbrains.jet.lang.resolve.Importer; 029import org.jetbrains.jet.lang.resolve.name.FqName; 030import org.jetbrains.jet.lang.resolve.name.LabelName; 031import org.jetbrains.jet.lang.resolve.name.Name; 032import org.jetbrains.jet.lang.resolve.scopes.*; 033 034import java.util.*; 035 036import static org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver.LookupMode; 037 038public class LazyImportScope implements JetScope { 039 private static class ImportResolveStatus { 040 private final LookupMode lookupMode; 041 private final JetScope scope; 042 043 ImportResolveStatus(LookupMode lookupMode, JetScope scope) { 044 this.lookupMode = lookupMode; 045 this.scope = scope; 046 } 047 } 048 049 private final ResolveSession resolveSession; 050 private final NamespaceDescriptor packageDescriptor; 051 private final ImportsProvider importsProvider; 052 private final JetScope rootScope; 053 private final BindingTrace traceForImportResolve; 054 private final String debugName; 055 056 private final Map<JetImportDirective, ImportResolveStatus> importedScopes = Maps.newHashMap(); 057 private JetImportDirective directiveUnderResolve = null; 058 059 public LazyImportScope( 060 @NotNull ResolveSession resolveSession, 061 @NotNull NamespaceDescriptor packageDescriptor, 062 @NotNull List<JetImportDirective> imports, 063 @NotNull BindingTrace traceForImportResolve, 064 @NotNull String debugName 065 ) { 066 this.resolveSession = resolveSession; 067 this.packageDescriptor = packageDescriptor; 068 this.importsProvider = new ImportsProvider(imports); 069 this.traceForImportResolve = traceForImportResolve; 070 this.debugName = debugName; 071 072 NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); 073 if (rootPackageDescriptor == null) { 074 throw new IllegalStateException("Root package not found"); 075 } 076 rootScope = rootPackageDescriptor.getMemberScope(); 077 } 078 079 public static LazyImportScope createImportScopeForFile( 080 @NotNull ResolveSession resolveSession, 081 @NotNull NamespaceDescriptor packageDescriptor, 082 @NotNull JetFile jetFile, 083 @NotNull BindingTrace traceForImportResolve, 084 @NotNull String debugName 085 ) { 086 return new LazyImportScope( 087 resolveSession, 088 packageDescriptor, 089 Lists.reverse(jetFile.getImportDirectives()), 090 traceForImportResolve, 091 debugName); 092 } 093 094 @Nullable 095 private <D extends DeclarationDescriptor> D selectFirstFromImports( 096 Name name, 097 LookupMode lookupMode, 098 JetScopeSelectorUtil.ScopeByNameSelector<D> descriptorSelector 099 ) { 100 for (JetImportDirective directive : importsProvider.getImports(name)) { 101 if (directive == directiveUnderResolve) { 102 // This is the recursion in imports analysis 103 return null; 104 } 105 106 D foundDescriptor = descriptorSelector.get(getImportScope(directive, lookupMode), name); 107 if (foundDescriptor != null) { 108 return foundDescriptor; 109 } 110 } 111 112 return null; 113 } 114 115 @NotNull 116 private <D extends DeclarationDescriptor> Collection<D> collectFromImports( 117 Name name, 118 LookupMode lookupMode, 119 JetScopeSelectorUtil.ScopeByNameMultiSelector<D> descriptorsSelector 120 ) { 121 Set<D> descriptors = Sets.newHashSet(); 122 for (JetImportDirective directive : importsProvider.getImports(name)) { 123 if (directive == directiveUnderResolve) { 124 // This is the recursion in imports analysis 125 throw new IllegalStateException("Recursion while resolving many imports: " + directive.getText()); 126 } 127 128 descriptors.addAll(descriptorsSelector.get(getImportScope(directive, lookupMode), name)); 129 } 130 131 return descriptors; 132 } 133 134 @NotNull 135 private <D extends DeclarationDescriptor> Collection<D> collectFromImports( 136 LookupMode lookupMode, 137 JetScopeSelectorUtil.ScopeDescriptorSelector<D> descriptorsSelector 138 ) { 139 Set<D> descriptors = Sets.newHashSet(); 140 for (JetImportDirective directive : importsProvider.getAllImports()) { 141 if (directive == directiveUnderResolve) { 142 // This is the recursion in imports analysis 143 throw new IllegalStateException("Recursion while resolving many imports: " + directive.getText()); 144 } 145 146 descriptors.addAll(descriptorsSelector.get(getImportScope(directive, lookupMode))); 147 } 148 149 return descriptors; 150 } 151 152 @NotNull 153 private JetScope getImportScope(JetImportDirective directive, LookupMode lookupMode) { 154 ImportResolveStatus status = importedScopes.get(directive); 155 if (status != null && (lookupMode == status.lookupMode || status.lookupMode == LookupMode.EVERYTHING)) { 156 return status.scope; 157 } 158 159 WritableScope directiveImportScope = new WritableScopeImpl( 160 JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, 161 "Scope for import '" + directive.getText() + "' resolve in " + toString()); 162 directiveImportScope.changeLockLevel(WritableScope.LockLevel.BOTH); 163 164 Importer.StandardImporter importer = new Importer.StandardImporter(directiveImportScope); 165 directiveUnderResolve = directive; 166 167 try { 168 resolveSession.getInjector().getQualifiedExpressionResolver().processImportReference( 169 directive, 170 rootScope, 171 packageDescriptor.getMemberScope(), 172 importer, 173 traceForImportResolve, 174 resolveSession.getRootModuleDescriptor(), 175 lookupMode); 176 } 177 finally { 178 directiveUnderResolve = null; 179 directiveImportScope.changeLockLevel(WritableScope.LockLevel.READING); 180 importedScopes.put(directive, new ImportResolveStatus(lookupMode, directiveImportScope)); 181 } 182 183 return directiveImportScope; 184 } 185 186 @Nullable 187 @Override 188 public ClassifierDescriptor getClassifier(@NotNull Name name) { 189 return selectFirstFromImports(name, LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.CLASSIFIER_DESCRIPTOR_SCOPE_SELECTOR); 190 } 191 192 @Nullable 193 @Override 194 public ClassDescriptor getObjectDescriptor(@NotNull Name name) { 195 return selectFirstFromImports(name, LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.NAMED_OBJECT_SCOPE_SELECTOR); 196 } 197 198 @NotNull 199 @Override 200 public Collection<ClassDescriptor> getObjectDescriptors() { 201 return collectFromImports(LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.OBJECTS_SCOPE_SELECTOR); 202 } 203 204 @Nullable 205 @Override 206 public NamespaceDescriptor getNamespace(@NotNull Name name) { 207 return selectFirstFromImports(name, LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.NAMESPACE_SCOPE_SELECTOR); 208 } 209 210 @NotNull 211 @Override 212 public Collection<VariableDescriptor> getProperties(@NotNull Name name) { 213 return collectFromImports(name, LookupMode.EVERYTHING, JetScopeSelectorUtil.NAMED_PROPERTIES_SCOPE_SELECTOR); 214 } 215 216 @Nullable 217 @Override 218 public VariableDescriptor getLocalVariable(@NotNull Name name) { 219 return null; 220 } 221 222 @NotNull 223 @Override 224 public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) { 225 return collectFromImports(name, LookupMode.EVERYTHING, JetScopeSelectorUtil.NAMED_FUNCTION_SCOPE_SELECTOR); 226 } 227 228 @NotNull 229 @Override 230 public DeclarationDescriptor getContainingDeclaration() { 231 return packageDescriptor; 232 } 233 234 @NotNull 235 @Override 236 public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) { 237 return Collections.emptyList(); 238 } 239 240 @Nullable 241 @Override 242 public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) { 243 return null; 244 } 245 246 @NotNull 247 @Override 248 public Collection<DeclarationDescriptor> getAllDescriptors() { 249 return collectFromImports(LookupMode.EVERYTHING, JetScopeSelectorUtil.ALL_DESCRIPTORS_SCOPE_SELECTOR); 250 } 251 252 @NotNull 253 @Override 254 public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() { 255 return Collections.emptyList(); 256 } 257 258 @NotNull 259 @Override 260 public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() { 261 return Collections.emptyList(); 262 } 263 264 @Override 265 public String toString() { 266 return "LazyImportScope: " + debugName; 267 } 268}