From 27bd74f4c53243faa5d2f7983edbc8dca547fe07 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 7 Apr 2016 19:15:14 +0300 Subject: [PATCH] Refactor: replace LastLineScopeProvider with ReplState, extract FileScopeFactory from FileScopeProviderImpl --- .../cli/jvm/repl/CliReplAnalyzerEngine.kt | 80 ++++--- .../kotlin/cli/jvm/repl/di/injection.kt | 6 +- .../jetbrains/kotlin/frontend/di/injection.kt | 3 +- .../kotlin/resolve/lazy/FileScopeFactory.kt | 218 ++++++++++++++++++ .../resolve/lazy/FileScopeProviderImpl.kt | 202 +--------------- .../kotlin/resolve/lazy/ResolveSession.java | 4 +- 6 files changed, 281 insertions(+), 232 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt index 9d7181c5ade..a225d12ec60 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/CliReplAnalyzerEngine.kt @@ -22,26 +22,24 @@ import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.config.getModuleName import org.jetbrains.kotlin.cli.jvm.repl.di.createContainerForReplWithJava -import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ScriptDescriptor import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtImportsFactory import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM -import org.jetbrains.kotlin.resolve.lazy.FileScopeProviderImpl +import org.jetbrains.kotlin.resolve.lazy.FileScopeFactory +import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider import org.jetbrains.kotlin.resolve.lazy.ResolveSession -import org.jetbrains.kotlin.resolve.lazy.TopLevelDescriptorProvider import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo import org.jetbrains.kotlin.resolve.lazy.declarations.* +import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.script.ScriptPriorities -import org.jetbrains.kotlin.storage.StorageManager class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) { private val topDownAnalysisContext: TopDownAnalysisContext @@ -49,8 +47,8 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) { private val resolveSession: ResolveSession private val scriptDeclarationFactory: ScriptMutableDeclarationProviderFactory val module: ModuleDescriptorImpl - private var lastLineScope: LexicalScope? = null val trace: BindingTraceContext = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace() + private val replState = ReplState() init { val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.getModuleName()) @@ -63,10 +61,7 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) { trace, scriptDeclarationFactory, ProjectScope.getAllScope(environment.project), - object : ReplLastLineScopeProvider { - override val lastLineScope: LexicalScope? - get() = this@CliReplAnalyzerEngine.lastLineScope - }, + replState, JvmPackagePartProvider(environment) ) @@ -105,24 +100,25 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) { return doAnalyze(psiFile) } - private fun doAnalyze(psiFile: KtFile): ReplLineAnalysisResult { - scriptDeclarationFactory.setDelegateFactory(FileBasedDeclarationProviderFactory(resolveSession.storageManager, listOf(psiFile))) + private fun doAnalyze(linePsi: KtFile): ReplLineAnalysisResult { + replState.submitLine(linePsi) + scriptDeclarationFactory.setDelegateFactory(FileBasedDeclarationProviderFactory(resolveSession.storageManager, listOf(linePsi))) - val context = topDownAnalyzer.analyzeDeclarations(topDownAnalysisContext.topDownAnalysisMode, listOf(psiFile)) + val context = topDownAnalyzer.analyzeDeclarations(topDownAnalysisContext.topDownAnalysisMode, listOf(linePsi)) - if (trace.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile) == null) { - trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile, resolveSession.getPackageFragment(FqName.ROOT)) + if (trace.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, linePsi) == null) { + trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, linePsi, resolveSession.getPackageFragment(FqName.ROOT)) } val diagnostics = trace.bindingContext.diagnostics val hasErrors = diagnostics.any { it.severity == Severity.ERROR } if (hasErrors) { + replState.lineFailure(linePsi) return ReplLineAnalysisResult.WithErrors(diagnostics) } else { - val scriptDescriptor = context.scripts[psiFile.script]!!.apply { - lastLineScope = this.scopeForInitializerResolution - } + val scriptDescriptor = context.scripts[linePsi.script]!! + replState.lineSuccess(linePsi, scriptDescriptor) return ReplLineAnalysisResult.Successful(scriptDescriptor, diagnostics) } @@ -172,20 +168,44 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) { } } -interface ReplLastLineScopeProvider { - val lastLineScope: LexicalScope? +class ReplState { + private val lines = hashMapOf() + private val successfulLines = arrayListOf() + + fun submitLine(ktFile: KtFile) { + lines[ktFile] = SubmittedLine(ktFile, successfulLines.lastOrNull()) + } + + fun lineSuccess(ktFile: KtFile, scriptDescriptor: LazyScriptDescriptor) { + val successfulLine = SuccessfulLine(ktFile, successfulLines.lastOrNull(), scriptDescriptor) + lines[ktFile] = successfulLine + successfulLines.add(successfulLine) + } + + fun lineFailure(ktFile: KtFile) { + lines[ktFile] = FailedLine(ktFile, successfulLines.lastOrNull()) + } + + fun lineInfo(ktFile: KtFile) = lines[ktFile] + + interface LineInfo { + val linePsi: KtFile + val parentLine: SuccessfulLine? + + val lexicalScopeBeforeThisLine: LexicalScope? get() = parentLine?.lineDescriptor?.scopeForInitializerResolution + } + + data class SubmittedLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?): LineInfo + data class SuccessfulLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?, val lineDescriptor: LazyScriptDescriptor): LineInfo + data class FailedLine(override val linePsi: KtFile, override val parentLine: SuccessfulLine?): LineInfo } class ReplFileScopeProvider( - private val lastLineScopeProvider: ReplLastLineScopeProvider, - topLevelDescriptorProvider: TopLevelDescriptorProvider, - storageManager: StorageManager, - moduleDescriptor: ModuleDescriptor, - qualifiedExpressionResolver: QualifiedExpressionResolver, - bindingTrace: BindingTrace, - ktImportsFactory: KtImportsFactory -) : FileScopeProviderImpl(topLevelDescriptorProvider, storageManager, moduleDescriptor, qualifiedExpressionResolver, bindingTrace, ktImportsFactory) { + private val replState: ReplState, + private val fileScopeFactory: FileScopeFactory +) : FileScopeProvider { + override fun getFileResolutionScope(file: KtFile) + = replState.lineInfo(file)?.lexicalScopeBeforeThisLine ?: fileScopeFactory.getLexicalScopeAndImportResolver(file).scope - override fun getFileResolutionScope(file: KtFile): LexicalScope - = lastLineScopeProvider.lastLineScope ?: super.getFileResolutionScope(file) + override fun getImportResolver(file: KtFile) = fileScopeFactory.getLexicalScopeAndImportResolver(file).importResolver } \ No newline at end of file diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/di/injection.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/di/injection.kt index 31280b33df9..cb3ff711e04 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/di/injection.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/di/injection.kt @@ -18,7 +18,7 @@ package org.jetbrains.kotlin.cli.jvm.repl.di import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.cli.jvm.repl.ReplFileScopeProvider -import org.jetbrains.kotlin.cli.jvm.repl.ReplLastLineScopeProvider +import org.jetbrains.kotlin.cli.jvm.repl.ReplState import org.jetbrains.kotlin.container.* import org.jetbrains.kotlin.context.ModuleContext import org.jetbrains.kotlin.descriptors.PackagePartProvider @@ -41,14 +41,14 @@ fun createContainerForReplWithJava( bindingTrace: BindingTrace, declarationProviderFactory: DeclarationProviderFactory, moduleContentScope: GlobalSearchScope, - lastLineScopeProvider: ReplLastLineScopeProvider, + replState: ReplState, packagePartProvider: PackagePartProvider ): ContainerForReplWithJava = createContainer("ReplWithJava") { useInstance(packagePartProvider) configureModule(moduleContext, JvmPlatform, bindingTrace) configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project, LookupTracker.DO_NOTHING) - useInstance(lastLineScopeProvider) + useInstance(replState) useImpl() useInstance(declarationProviderFactory) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt b/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt index dc646fbd71a..5797e9f1a49 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -125,6 +125,7 @@ fun createContainerForLazyResolve( useInstance(declarationProviderFactory) useInstance(LookupTracker.DO_NOTHING) + useImpl() targetEnvironment.configure(this) useImpl() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt new file mode 100644 index 00000000000..cc43145593a --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt @@ -0,0 +1,218 @@ +/* + * Copyright 2010-2016 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.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtImportDirective +import org.jetbrains.kotlin.psi.KtImportsFactory +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver +import org.jetbrains.kotlin.resolve.TemporaryBindingTrace +import org.jetbrains.kotlin.resolve.bindingContextUtil.recordScope +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.ImportingScope +import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.SubpackagesImportingScope +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.storage.getValue +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.utils.Printer +import org.jetbrains.kotlin.utils.addToStdlib.check + +class FileScopeFactory( + private val topLevelDescriptorProvider: TopLevelDescriptorProvider, + private val storageManager: StorageManager, + private val moduleDescriptor: ModuleDescriptor, + private val qualifiedExpressionResolver: QualifiedExpressionResolver, + private val bindingTrace: BindingTrace, + private val ktImportsFactory: KtImportsFactory +) { + + class FileData(val scope: LexicalScope, val importResolver: ImportResolver) + + fun getLexicalScopeAndImportResolver(file: KtFile): FileData = cache(file) + + private val defaultImports by storageManager.createLazyValue { + ktImportsFactory.createImportDirectives(moduleDescriptor.defaultImports) + } + + private val cache = storageManager.createMemoizedFunction { file: KtFile -> createScopeChainAndImportResolver(file) } + + private fun createScopeChainAndImportResolver(file: KtFile): FileData { + val debugName = "LazyFileScope for file " + file.name + val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve") + + val imports = file.importDirectives + + val aliasImportNames = imports.mapNotNull { if (it.aliasName != null) it.importedFqName else null } + + val packageView = moduleDescriptor.getPackage(file.packageFqName) + val packageFragment = topLevelDescriptorProvider.getPackageFragment(file.packageFqName) + ?: error("Could not find fragment ${file.packageFqName} for file ${file.name}") + + fun createImportResolver(indexedImports: IndexedImports, trace: BindingTrace) + = LazyImportResolver(storageManager, qualifiedExpressionResolver, moduleDescriptor, indexedImports, aliasImportNames, trace, packageFragment) + + val explicitImportResolver = createImportResolver(ExplicitImportsIndexed(imports), bindingTrace) + val allUnderImportResolver = createImportResolver(AllUnderImportsIndexed(imports), bindingTrace) + + val defaultImportsFiltered = if (aliasImportNames.isEmpty()) { // optimization + defaultImports + } + else { + defaultImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames } + } + val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace) + val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace) + + val dummyContainerDescriptor = DummyContainerDescriptor(file, packageFragment) + + var scope: ImportingScope + + scope = LazyImportScope(null, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, + "Default all under imports in $debugName (invisible classes only)") + + scope = LazyImportScope(scope, allUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, + "All under imports in $debugName (invisible classes only)") + + scope = currentPackageScope(packageView, aliasImportNames, dummyContainerDescriptor, FilteringKind.INVISIBLE_CLASSES, scope) + + scope = LazyImportScope(scope, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, + "Default all under imports in $debugName (visible classes)") + + scope = LazyImportScope(scope, allUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, + "All under imports in $debugName (visible classes)") + + scope = LazyImportScope(scope, defaultExplicitImportResolver, LazyImportScope.FilteringKind.ALL, + "Default explicit imports in $debugName") + + scope = SubpackagesImportingScope(scope, moduleDescriptor, FqName.ROOT) + + scope = currentPackageScope(packageView, aliasImportNames, dummyContainerDescriptor, FilteringKind.VISIBLE_CLASSES, scope) + + scope = LazyImportScope(scope, explicitImportResolver, LazyImportScope.FilteringKind.ALL, "Explicit imports in $debugName") + + val lexicalScope = LexicalScope.empty(scope, packageFragment) + + bindingTrace.recordScope(lexicalScope, file) + + val importResolver = object : ImportResolver { + override fun forceResolveAllImports() { + explicitImportResolver.forceResolveAllImports() + allUnderImportResolver.forceResolveAllImports() + } + + override fun forceResolveImport(importDirective: KtImportDirective) { + if (importDirective.isAllUnder) { + allUnderImportResolver.forceResolveImport(importDirective) + } + else { + explicitImportResolver.forceResolveImport(importDirective) + } + } + } + + return FileData(lexicalScope, importResolver) + } + + private enum class FilteringKind { + VISIBLE_CLASSES, INVISIBLE_CLASSES + } + + private fun currentPackageScope( + packageView: PackageViewDescriptor, + aliasImportNames: Collection, + fromDescriptor: DummyContainerDescriptor, + filteringKind: FilteringKind, + parentScope: ImportingScope + ): ImportingScope { + val scope = packageView.memberScope + val packageName = packageView.fqName + val excludedNames = aliasImportNames.mapNotNull { if (it.parent() == packageName) it.shortName() else null } + + return object : ImportingScope { + override val parent: ImportingScope? = parentScope + + override fun getContributedPackage(name: Name) = null + + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { + if (name in excludedNames) return null + val classifier = scope.getContributedClassifier(name, location) ?: return null + val visible = Visibilities.isVisibleIgnoringReceiver(classifier as DeclarationDescriptorWithVisibility, fromDescriptor) + return classifier.check { filteringKind == if (visible) FilteringKind.VISIBLE_CLASSES else FilteringKind.INVISIBLE_CLASSES } + } + + override fun getContributedVariables(name: Name, location: LookupLocation): Collection { + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() + if (name in excludedNames) return emptyList() + return scope.getContributedVariables(name, location) + } + + override fun getContributedFunctions(name: Name, location: LookupLocation): Collection { + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() + if (name in excludedNames) return emptyList() + return scope.getContributedFunctions(name, location) + } + + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { + // we do not perform any filtering by visibility here because all descriptors from both visible/invisible filter scopes are to be added anyway + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() + return scope.getContributedDescriptors( + kindFilter.withoutKinds(DescriptorKindFilter.PACKAGES_MASK), + { name -> name !in excludedNames && nameFilter(name) } + ).filter { it !is PackageViewDescriptor } // subpackages of the current package not accessible by the short name + } + + override fun toString() = "Scope for current package (${filteringKind.name})" + + override fun printStructure(p: Printer) { + p.println(this.toString()) + } + } + } + + // we use this dummy implementation of DeclarationDescriptor to check accessibility of symbols from the current package + private class DummyContainerDescriptor(file: KtFile, private val packageFragment: PackageFragmentDescriptor) : DeclarationDescriptorNonRoot { + private val sourceElement = KotlinSourceElement(file) + + override fun getContainingDeclaration() = packageFragment + + override fun getSource() = sourceElement + + override fun getOriginal() = this + override val annotations: Annotations get() = Annotations.EMPTY + override fun substitute(substitutor: TypeSubstitutor) = this + + override fun accept(visitor: DeclarationDescriptorVisitor?, data: D): R { + throw UnsupportedOperationException() + } + + override fun acceptVoid(visitor: DeclarationDescriptorVisitor?) { + throw UnsupportedOperationException() + } + + override fun getName(): Name { + throw UnsupportedOperationException() + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt index 101e5b59538..597906703ed 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt @@ -16,205 +16,15 @@ package org.jetbrains.kotlin.resolve.lazy -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.incremental.components.LookupLocation -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtImportDirective -import org.jetbrains.kotlin.psi.KtImportsFactory -import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver -import org.jetbrains.kotlin.resolve.TemporaryBindingTrace -import org.jetbrains.kotlin.resolve.bindingContextUtil.recordScope -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope -import org.jetbrains.kotlin.resolve.scopes.SubpackagesImportingScope -import org.jetbrains.kotlin.resolve.source.KotlinSourceElement -import org.jetbrains.kotlin.storage.StorageManager -import org.jetbrains.kotlin.storage.getValue -import org.jetbrains.kotlin.types.TypeSubstitutor -import org.jetbrains.kotlin.utils.Printer -import org.jetbrains.kotlin.utils.addToStdlib.check -open class FileScopeProviderImpl( - private val topLevelDescriptorProvider: TopLevelDescriptorProvider, - private val storageManager: StorageManager, - private val moduleDescriptor: ModuleDescriptor, - private val qualifiedExpressionResolver: QualifiedExpressionResolver, - private val bindingTrace: BindingTrace, - private val ktImportsFactory: KtImportsFactory -) : FileScopeProvider { - - private val defaultImports by storageManager.createLazyValue { - ktImportsFactory.createImportDirectives(moduleDescriptor.defaultImports) +class FileScopeProviderImpl(private val fileScopeFactory: FileScopeFactory) : FileScopeProvider { + override fun getFileResolutionScope(file: KtFile): LexicalScope { + return fileScopeFactory.getLexicalScopeAndImportResolver(file).scope } - private class FileData(val scope: LexicalScope, val importResolver: ImportResolver) - - private val cache = storageManager.createMemoizedFunction { file: KtFile -> createScopeChainAndImportResolver(file) } - - override fun getFileResolutionScope(file: KtFile) = cache(file).scope - - override fun getImportResolver(file: KtFile) = cache(file).importResolver - - private fun createScopeChainAndImportResolver(file: KtFile): FileData { - val debugName = "LazyFileScope for file " + file.name - val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve") - - val imports = file.importDirectives - - val aliasImportNames = imports.mapNotNull { if (it.aliasName != null) it.importedFqName else null } - - val packageView = moduleDescriptor.getPackage(file.packageFqName) - val packageFragment = topLevelDescriptorProvider.getPackageFragment(file.packageFqName) - ?: error("Could not find fragment ${file.packageFqName} for file ${file.name}") - - fun createImportResolver(indexedImports: IndexedImports, trace: BindingTrace) - = LazyImportResolver(storageManager, qualifiedExpressionResolver, moduleDescriptor, indexedImports, aliasImportNames, trace, packageFragment) - - val explicitImportResolver = createImportResolver(ExplicitImportsIndexed(imports), bindingTrace) - val allUnderImportResolver = createImportResolver(AllUnderImportsIndexed(imports), bindingTrace) - - val defaultImportsFiltered = if (aliasImportNames.isEmpty()) { // optimization - defaultImports - } - else { - defaultImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames } - } - val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace) - val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace) - - val dummyContainerDescriptor = DummyContainerDescriptor(file, packageFragment) - - var scope: ImportingScope - - scope = LazyImportScope(null, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, - "Default all under imports in $debugName (invisible classes only)") - - scope = LazyImportScope(scope, allUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, - "All under imports in $debugName (invisible classes only)") - - scope = currentPackageScope(packageView, aliasImportNames, dummyContainerDescriptor, FilteringKind.INVISIBLE_CLASSES, scope) - - scope = LazyImportScope(scope, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, - "Default all under imports in $debugName (visible classes)") - - scope = LazyImportScope(scope, allUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, - "All under imports in $debugName (visible classes)") - - scope = LazyImportScope(scope, defaultExplicitImportResolver, LazyImportScope.FilteringKind.ALL, - "Default explicit imports in $debugName") - - scope = SubpackagesImportingScope(scope, moduleDescriptor, FqName.ROOT) - - scope = currentPackageScope(packageView, aliasImportNames, dummyContainerDescriptor, FilteringKind.VISIBLE_CLASSES, scope) - - scope = LazyImportScope(scope, explicitImportResolver, LazyImportScope.FilteringKind.ALL, "Explicit imports in $debugName") - - val lexicalScope = LexicalScope.empty(scope, packageFragment) - - bindingTrace.recordScope(lexicalScope, file) - - val importResolver = object : ImportResolver { - override fun forceResolveAllImports() { - explicitImportResolver.forceResolveAllImports() - allUnderImportResolver.forceResolveAllImports() - } - - override fun forceResolveImport(importDirective: KtImportDirective) { - if (importDirective.isAllUnder) { - allUnderImportResolver.forceResolveImport(importDirective) - } - else { - explicitImportResolver.forceResolveImport(importDirective) - } - } - } - - return FileData(lexicalScope, importResolver) + override fun getImportResolver(file: KtFile): ImportResolver { + return fileScopeFactory.getLexicalScopeAndImportResolver(file).importResolver } - - private enum class FilteringKind { - VISIBLE_CLASSES, INVISIBLE_CLASSES - } - - private fun currentPackageScope( - packageView: PackageViewDescriptor, - aliasImportNames: Collection, - fromDescriptor: DummyContainerDescriptor, - filteringKind: FilteringKind, - parentScope: ImportingScope - ): ImportingScope { - val scope = packageView.memberScope - val packageName = packageView.fqName - val excludedNames = aliasImportNames.mapNotNull { if (it.parent() == packageName) it.shortName() else null } - - return object: ImportingScope { - override val parent: ImportingScope? = parentScope - - override fun getContributedPackage(name: Name) = null - - override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { - if (name in excludedNames) return null - val classifier = scope.getContributedClassifier(name, location) ?: return null - val visible = Visibilities.isVisibleIgnoringReceiver(classifier as DeclarationDescriptorWithVisibility, fromDescriptor) - return classifier.check { filteringKind == if (visible) FilteringKind.VISIBLE_CLASSES else FilteringKind.INVISIBLE_CLASSES } - } - - override fun getContributedVariables(name: Name, location: LookupLocation): Collection { - if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() - if (name in excludedNames) return emptyList() - return scope.getContributedVariables(name, location) - } - - override fun getContributedFunctions(name: Name, location: LookupLocation): Collection { - if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() - if (name in excludedNames) return emptyList() - return scope.getContributedFunctions(name, location) - } - - override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { - // we do not perform any filtering by visibility here because all descriptors from both visible/invisible filter scopes are to be added anyway - if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() - return scope.getContributedDescriptors( - kindFilter.withoutKinds(DescriptorKindFilter.PACKAGES_MASK), - { name -> name !in excludedNames && nameFilter(name) } - ).filter { it !is PackageViewDescriptor } // subpackages of the current package not accessible by the short name - } - - override fun toString() = "Scope for current package (${filteringKind.name})" - - override fun printStructure(p: Printer) { - p.println(this.toString()) - } - } - } - - // we use this dummy implementation of DeclarationDescriptor to check accessibility of symbols from the current package - private class DummyContainerDescriptor(file: KtFile, private val packageFragment: PackageFragmentDescriptor) : DeclarationDescriptorNonRoot { - private val sourceElement = KotlinSourceElement(file) - - override fun getContainingDeclaration() = packageFragment - - override fun getSource() = sourceElement - - override fun getOriginal() = this - override val annotations: Annotations get() = Annotations.EMPTY - override fun substitute(substitutor: TypeSubstitutor) = this - - override fun accept(visitor: DeclarationDescriptorVisitor?, data: D): R { - throw UnsupportedOperationException() - } - - override fun acceptVoid(visitor: DeclarationDescriptorVisitor?) { - throw UnsupportedOperationException() - } - - override fun getName(): Name { - throw UnsupportedOperationException() - } - } -} +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java index e5b28f83ff5..d0f1958e93f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java @@ -42,8 +42,8 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.PackageMemberDeclarationPr import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotations; import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationsContextImpl; import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor; -import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope; +import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.storage.*; import javax.inject.Inject; @@ -109,7 +109,7 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext { } @Inject - public void setFileScopeProvider(@NotNull FileScopeProviderImpl fileScopeProvider) { + public void setFileScopeProvider(@NotNull FileScopeProvider fileScopeProvider) { this.fileScopeProvider = fileScopeProvider; }