diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.java index 9efe5fdfa07..2ab57efc908 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.java @@ -29,7 +29,7 @@ import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer; -import org.jetbrains.kotlin.resolve.lazy.LazyImportScope; +import org.jetbrains.kotlin.resolve.lazy.LazyFileScope; import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor; import org.jetbrains.kotlin.resolve.resolveUtil.ResolveUtilPackage; import org.jetbrains.kotlin.resolve.varianceChecker.VarianceChecker; @@ -193,8 +193,9 @@ public class LazyTopDownAnalyzer { @Override public void visitImportDirective(@NotNull JetImportDirective importDirective) { - LazyImportScope importScope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(importDirective.getContainingJetFile()); - importScope.forceResolveImportDirective(importDirective); + LazyFileScope fileScope = resolveSession.getScopeProvider().getScopeForFile( + importDirective.getContainingJetFile()); + fileScope.forceResolveImportDirective(importDirective); } private void visitClassOrObject(@NotNull JetClassOrObject classOrObject) { @@ -363,7 +364,7 @@ public class LazyTopDownAnalyzer { } private static void resolveAndCheckImports(@NotNull JetFile file, @NotNull KotlinCodeAnalyzer resolveSession) { - LazyImportScope fileScope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(file); + LazyFileScope fileScope = resolveSession.getScopeProvider().getScopeForFile(file); fileScope.forceResolveAllContents(); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ImportsProvider.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ImportsProvider.java deleted file mode 100644 index 2bb288ce225..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ImportsProvider.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.resolve.lazy; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableListMultimap; -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Lists; -import kotlin.Function0; -import kotlin.KotlinPackage; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.JetImportDirective; -import org.jetbrains.kotlin.resolve.ImportPath; -import org.jetbrains.kotlin.storage.NotNullLazyValue; -import org.jetbrains.kotlin.storage.StorageManager; - -import java.util.Collections; -import java.util.List; - -class ImportsProvider { - private final List importDirectives; - private final NotNullLazyValue importsCacheValue; - - public ImportsProvider(StorageManager storageManager, final List importDirectives) { - this.importDirectives = importDirectives; - this.importsCacheValue = storageManager.createLazyValue(new Function0() { - @Override - public NameToImportsCache invoke() { - return NameToImportsCache.createIndex(importDirectives); - } - }); - } - - @NotNull - public List getImports(@NotNull Name name, @NotNull LookupMode mode) { - return importsCacheValue.invoke().getImports(name, mode); - } - - @NotNull - public List getAllImports() { - return importDirectives; - } - - public enum LookupMode { - CLASS, - PACKAGE, - FUNCTION_OR_PROPERTY - } - - private static class NameToImportsCache { - private final ListMultimap nameToDirectives; - private final List allUnderImports; - - private NameToImportsCache(ListMultimap directives, List imports) { - nameToDirectives = directives; - allUnderImports = imports; - } - - private List getImports(@NotNull Name name, @NotNull LookupMode mode) { - switch (mode) { - case CLASS: - return nameToDirectives.containsKey(name) ? nameToDirectives.get(name) : allUnderImports; // for class lookup explicit imports have priority - - case PACKAGE: - return nameToDirectives.containsKey(name) ? nameToDirectives.get(name) : Collections.emptyList(); // no packages import by all under imports - - case FUNCTION_OR_PROPERTY: - return nameToDirectives.containsKey(name) ? KotlinPackage.plus(nameToDirectives.get(name), allUnderImports) : allUnderImports; - - default: - throw new IllegalArgumentException(); - } - } - - private static NameToImportsCache createIndex(List importDirectives) { - ImmutableListMultimap.Builder namesToRelativeImportsBuilder = ImmutableListMultimap.builder(); - - List allUnderImports = Lists.newArrayList(); - - for (JetImportDirective anImport : importDirectives) { - ImportPath path = anImport.getImportPath(); - if (path == null) continue; // Could be some parse errors - - if (path.isAllUnder()) { - allUnderImports.add(anImport); - } - else { - Name aliasName = path.getImportedName(); - assert aliasName != null; - namesToRelativeImportsBuilder.put(aliasName, anImport); - } - } - - return new NameToImportsCache(namesToRelativeImportsBuilder.build(), ImmutableList.copyOf(allUnderImports)); - } - } -} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyFileScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyFileScope.kt new file mode 100644 index 00000000000..36e97db96a6 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyFileScope.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.lazy + +import org.jetbrains.kotlin.descriptors.PackageViewDescriptor +import org.jetbrains.kotlin.resolve.scopes.ChainedScope +import org.jetbrains.kotlin.psi.JetImportDirective +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.psi.JetCodeFragment + +class LazyFileScope private( + private val aliasImportsScope: LazyImportScope, + private val allUnderImportsScope: LazyImportScope, + private val defaultAliasImportsScope: LazyImportScope, + private val defaultAllUnderImportsScope: LazyImportScope, + containingDeclaration: PackageViewDescriptor, + debugName: String +) : ChainedScope(containingDeclaration, debugName, aliasImportsScope, allUnderImportsScope, defaultAliasImportsScope, defaultAllUnderImportsScope) { + + public fun forceResolveAllContents() { + aliasImportsScope.forceResolveAllContents() + allUnderImportsScope.forceResolveAllContents() + } + + public fun forceResolveImportDirective(importDirective: JetImportDirective) { + if (importDirective.isAllUnder()) { + allUnderImportsScope.forceResolveImportDirective(importDirective) + } + else { + aliasImportsScope.forceResolveImportDirective(importDirective) + } + } + + class object { + public fun create( + resolveSession: ResolveSession, + packageDescriptor: PackageViewDescriptor, + jetFile: JetFile, + defaultImports: Collection, + traceForImportResolve: BindingTrace, + traceForDefaultImportResolve: BindingTrace, + debugName: String + ): LazyFileScope { + val imports = if (jetFile is JetCodeFragment) + jetFile.importsAsImportList()?.getImports() ?: listOf() + else + jetFile.getImportDirectives() + + val aliasImportsScope = LazyImportScope(resolveSession, packageDescriptor, AliasImportsIndexed(imports), traceForImportResolve, "Alias imports in $debugName") + val allUnderImportsScope = LazyImportScope(resolveSession, packageDescriptor, AllUnderImportsIndexed(imports), traceForImportResolve, "All under imports in $debugName") + val defaultAliasImportsScope = LazyImportScope(resolveSession, packageDescriptor, AliasImportsIndexed(defaultImports), traceForDefaultImportResolve, "Default alias imports in $debugName") + val defaultAllUnderImportsScope = LazyImportScope(resolveSession, packageDescriptor, AllUnderImportsIndexed(defaultImports), traceForDefaultImportResolve, "Default all under imports in $debugName") + return LazyFileScope(aliasImportsScope, allUnderImportsScope, defaultAliasImportsScope, defaultAllUnderImportsScope, packageDescriptor, debugName) + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt index 769b3112197..74d0c365f75 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -17,8 +17,6 @@ package org.jetbrains.kotlin.resolve.lazy import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.psi.JetCodeFragment -import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.JetImportDirective import org.jetbrains.kotlin.psi.debugText.* import org.jetbrains.kotlin.resolve.BindingTrace @@ -32,18 +30,49 @@ import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.LookupMode import java.util.LinkedHashSet import java.util.HashSet +import com.google.common.collect.ListMultimap +import kotlin.properties.Delegates +import com.google.common.collect.ImmutableListMultimap -public class LazyImportScope(private val resolveSession: ResolveSession, - private val containingDeclaration: PackageViewDescriptor, - imports: List, - private val traceForImportResolve: BindingTrace, - private val debugName: String, - inRootPackage: Boolean) : JetScope { +trait IndexedImports { + val imports: List + fun importsForName(name: Name): Collection +} + +class AllUnderImportsIndexed(allImports: Collection) : IndexedImports { + override val imports = allImports.filter { it.isAllUnder() } + override fun importsForName(name: Name) = imports +} + +class AliasImportsIndexed(allImports: Collection) : IndexedImports { + override val imports = allImports.filter { !it.isAllUnder() } + + private val nameToDirectives: ListMultimap by Delegates.lazy { + val builder = ImmutableListMultimap.builder() + + for (directive in imports) { + val path = directive.getImportPath() ?: continue // can be some parse errors + builder.put(path.getImportedName()!!, directive) + } + + builder.build() + } + + override fun importsForName(name: Name) = nameToDirectives.get(name) +} + +class LazyImportScope( + private val resolveSession: ResolveSession, + private val containingDeclaration: PackageViewDescriptor, + private val indexedImports: IndexedImports, + private val traceForImportResolve: BindingTrace, + private val debugName: String +) : JetScope { - private val importsProvider = ImportsProvider(resolveSession.getStorageManager(), imports) private val importedScopesProvider = resolveSession.getStorageManager().createMemoizedFunction { (directive: JetImportDirective) -> ImportDirectiveResolveCache(directive) } + private val inRootPackage = containingDeclaration.getFqName().isRoot() private val rootScope = JetModuleUtil.getImportsResolutionScope(resolveSession.getModuleDescriptor(), inRootPackage) private var directiveUnderResolve: JetImportDirective? = null @@ -95,7 +124,7 @@ public class LazyImportScope(private val resolveSession: ResolveSession, } public fun forceResolveAllContents() { - for (importDirective in importsProvider.getAllImports()) { + for (importDirective in indexedImports.imports) { forceResolveImportDirective(importDirective) } } @@ -113,12 +142,10 @@ public class LazyImportScope(private val resolveSession: ResolveSession, private fun selectSingleFromImports( name: Name, lookupMode: LookupMode, - selectImportsMode: ImportsProvider.LookupMode, descriptorSelector: JetScopeSelectorUtil.ScopeByNameSelector ): D? { fun compute(): D? { - // for classes and packages it never returns a mix of explicit and all-under imports so they all have the same priority - val imports = importsProvider.getImports(name, selectImportsMode) + val imports = indexedImports.importsForName(name) if (imports.contains(directiveUnderResolve)) { // This is the recursion in imports analysis return null @@ -138,12 +165,11 @@ public class LazyImportScope(private val resolveSession: ResolveSession, private fun collectFromImports( name: Name, lookupMode: LookupMode, - selectImportsMode: ImportsProvider.LookupMode, descriptorsSelector: JetScopeSelectorUtil.ScopeByNameMultiSelector ): Collection { return resolveSession.getStorageManager().compute { val descriptors = HashSet() - for (directive in importsProvider.getImports(name, selectImportsMode)) { + for (directive in indexedImports.importsForName(name)) { if (directive == directiveUnderResolve) { // This is the recursion in imports analysis throw IllegalStateException("Recursion while resolving many imports: " + directive.getText()) @@ -158,22 +184,22 @@ public class LazyImportScope(private val resolveSession: ResolveSession, private fun getImportScope(directive: JetImportDirective, lookupMode: LookupMode) = importedScopesProvider(directive).scopeForMode(lookupMode) - override fun getClassifier(name: Name) = selectSingleFromImports(name, LookupMode.ONLY_CLASSES_AND_PACKAGES, ImportsProvider.LookupMode.CLASS, JetScopeSelectorUtil.CLASSIFIER_DESCRIPTOR_SCOPE_SELECTOR) + override fun getClassifier(name: Name) = selectSingleFromImports(name, LookupMode.ONLY_CLASSES_AND_PACKAGES, JetScopeSelectorUtil.CLASSIFIER_DESCRIPTOR_SCOPE_SELECTOR) - override fun getPackage(name: Name) = selectSingleFromImports(name, LookupMode.ONLY_CLASSES_AND_PACKAGES, ImportsProvider.LookupMode.PACKAGE, JetScopeSelectorUtil.PACKAGE_SCOPE_SELECTOR) + override fun getPackage(name: Name) = selectSingleFromImports(name, LookupMode.ONLY_CLASSES_AND_PACKAGES, JetScopeSelectorUtil.PACKAGE_SCOPE_SELECTOR) - override fun getProperties(name: Name) = collectFromImports(name, LookupMode.EVERYTHING, ImportsProvider.LookupMode.FUNCTION_OR_PROPERTY, JetScopeSelectorUtil.NAMED_PROPERTIES_SCOPE_SELECTOR) + override fun getProperties(name: Name) = collectFromImports(name, LookupMode.EVERYTHING, JetScopeSelectorUtil.NAMED_PROPERTIES_SCOPE_SELECTOR) override fun getLocalVariable(name: Name) = null - override fun getFunctions(name: Name) = collectFromImports(name, LookupMode.EVERYTHING, ImportsProvider.LookupMode.FUNCTION_OR_PROPERTY, JetScopeSelectorUtil.NAMED_FUNCTION_SCOPE_SELECTOR) + override fun getFunctions(name: Name) = collectFromImports(name, LookupMode.EVERYTHING, JetScopeSelectorUtil.NAMED_FUNCTION_SCOPE_SELECTOR) override fun getDeclarationsByLabel(labelName: Name): Collection = listOf() override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { return resolveSession.getStorageManager().compute { val descriptors = LinkedHashSet() - for (directive in importsProvider.getAllImports()) { + for (directive in indexedImports.imports) { if (directive == directiveUnderResolve) { // This is the recursion in imports analysis throw IllegalStateException("Recursion while resolving many imports: " + directive.getText()) @@ -210,21 +236,4 @@ public class LazyImportScope(private val resolveSession: ResolveSession, p.popIndent() p.println("}") } - - class object { - public fun createImportScopeForFile(resolveSession: ResolveSession, - packageDescriptor: PackageViewDescriptor, - jetFile: JetFile, - traceForImportResolve: BindingTrace, - debugName: String): LazyImportScope { - val importDirectives: List = if (jetFile is JetCodeFragment) { - jetFile.importsAsImportList()?.getImports() ?: listOf() - } - else { - jetFile.getImportDirectives() - } - - return LazyImportScope(resolveSession, packageDescriptor, importDirectives.reverse(), traceForImportResolve, debugName, packageDescriptor.getFqName().isRoot()) - } - } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ScopeProvider.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ScopeProvider.java index db1b1e63cc3..3a52789a71d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ScopeProvider.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ScopeProvider.java @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.resolve.lazy; -import com.google.common.collect.Lists; import com.intellij.psi.PsiElement; import kotlin.Function0; import kotlin.Function1; @@ -50,9 +49,9 @@ public class ScopeProvider { private final ResolveSession resolveSession; - private final MemoizedFunctionToNotNull explicitImportScopes; + private final NotNullLazyValue> defaultImports; - private final NotNullLazyValue defaultImportsScope; + private final MemoizedFunctionToNotNull importScopes; private final MemoizedFunctionToNotNull fileScopes; @@ -64,20 +63,29 @@ public class ScopeProvider { this.additionalFileScopeProvider = additionalFileScopeProvider; } - public ScopeProvider(@NotNull ResolveSession resolveSession) { + public ScopeProvider(@NotNull final ResolveSession resolveSession) { this.resolveSession = resolveSession; - this.explicitImportScopes = resolveSession.getStorageManager().createMemoizedFunction(new Function1() { + this.defaultImports = resolveSession.getStorageManager().createLazyValue(new Function0>() { @Override - public LazyImportScope invoke(@NotNull JetFile file) { - return createExplicitImportScope(file); + public Collection invoke() { + PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT); + if (rootPackage == null) { + throw new IllegalStateException("Root package not found"); + } + + JetImportsFactory importsFactory = resolveSession.getJetImportsFactory(); + List defaultImports = resolveSession.getModuleDescriptor().getDefaultImports(); + + return importsFactory.createImportDirectives(defaultImports); } }); - this.defaultImportsScope = resolveSession.getStorageManager().createLazyValue(new Function0() { + + this.importScopes = resolveSession.getStorageManager().createMemoizedFunction(new Function1() { @Override - public JetScope invoke() { - return createScopeWithDefaultImports(); + public LazyFileScope invoke(@NotNull JetFile file) { + return createImportScope(file, defaultImports.invoke()); } }); @@ -89,13 +97,16 @@ public class ScopeProvider { }); } - private LazyImportScope createExplicitImportScope(@NotNull JetFile file) { - return LazyImportScope.OBJECT$.createImportScopeForFile( + private LazyFileScope createImportScope(@NotNull JetFile file, @NotNull Collection defaultImports) { + TemporaryBindingTrace tempTrace = TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"); + return LazyFileScope.OBJECT$.create( resolveSession, getFilePackageDescriptor(file), file, + defaultImports, resolveSession.getTrace(), - "Lazy Imports Scope for file " + file.getName()); + tempTrace, + "LazyFileScope for file " + file.getName()); } @NotNull @@ -114,36 +125,15 @@ public class ScopeProvider { List list = new ArrayList(); list.add(new NoSubpackagesInPackageScope(getFilePackageDescriptor(file))); list.add(JetModuleUtil.getSubpackagesOfRootScope(resolveSession.getModuleDescriptor())); - list.add(explicitImportScopes.invoke(file)); + list.add(importScopes.invoke(file)); list.addAll(additionalFileScopeProvider.scopes(file)); - list.add(defaultImportsScope.invoke()); return list.toArray(new JetScope[list.size()]); } @NotNull - public LazyImportScope getExplicitImportsScopeForFile(@NotNull JetFile file) { - return explicitImportScopes.invoke(file); - } - - private JetScope createScopeWithDefaultImports() { - PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT); - if (rootPackage == null) { - throw new IllegalStateException("Root package not found"); - } - - JetImportsFactory importsFactory = resolveSession.getJetImportsFactory(); - List defaultImports = resolveSession.getModuleDescriptor().getDefaultImports(); - - Collection defaultImportDirectives = importsFactory.createImportDirectives(defaultImports); - - return new LazyImportScope( - resolveSession, - rootPackage, - Lists.reverse(Lists.newArrayList(defaultImportDirectives)), - TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"), - "Lazy default imports scope", - false); + public LazyFileScope getScopeForFile(@NotNull JetFile file) { + return importScopes.invoke(file); } @NotNull diff --git a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.java b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.java index 8a208148407..9be0004aacd 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.java +++ b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.java @@ -160,7 +160,7 @@ public abstract class ElementResolver { } else if (resolveElement instanceof JetImportDirective) { JetImportDirective importDirective = (JetImportDirective) resolveElement; - LazyImportScope scope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(importDirective.getContainingJetFile()); + LazyFileScope scope = resolveSession.getScopeProvider().getScopeForFile(importDirective.getContainingJetFile()); scope.forceResolveAllContents(); } else if (resolveElement instanceof JetAnnotationEntry) {