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