Refactor: replace LastLineScopeProvider with ReplState, extract FileScopeFactory from FileScopeProviderImpl
This commit is contained in:
@@ -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.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.getModuleName
|
import org.jetbrains.kotlin.cli.jvm.config.getModuleName
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.di.createContainerForReplWithJava
|
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.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtImportsFactory
|
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
|
||||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
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.ResolveSession
|
||||||
import org.jetbrains.kotlin.resolve.lazy.TopLevelDescriptorProvider
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo
|
import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.*
|
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.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
|
||||||
|
|
||||||
class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) {
|
class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) {
|
||||||
private val topDownAnalysisContext: TopDownAnalysisContext
|
private val topDownAnalysisContext: TopDownAnalysisContext
|
||||||
@@ -49,8 +47,8 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) {
|
|||||||
private val resolveSession: ResolveSession
|
private val resolveSession: ResolveSession
|
||||||
private val scriptDeclarationFactory: ScriptMutableDeclarationProviderFactory
|
private val scriptDeclarationFactory: ScriptMutableDeclarationProviderFactory
|
||||||
val module: ModuleDescriptorImpl
|
val module: ModuleDescriptorImpl
|
||||||
private var lastLineScope: LexicalScope? = null
|
|
||||||
val trace: BindingTraceContext = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
|
val trace: BindingTraceContext = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
|
||||||
|
private val replState = ReplState()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.getModuleName())
|
val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.getModuleName())
|
||||||
@@ -63,10 +61,7 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) {
|
|||||||
trace,
|
trace,
|
||||||
scriptDeclarationFactory,
|
scriptDeclarationFactory,
|
||||||
ProjectScope.getAllScope(environment.project),
|
ProjectScope.getAllScope(environment.project),
|
||||||
object : ReplLastLineScopeProvider {
|
replState,
|
||||||
override val lastLineScope: LexicalScope?
|
|
||||||
get() = this@CliReplAnalyzerEngine.lastLineScope
|
|
||||||
},
|
|
||||||
JvmPackagePartProvider(environment)
|
JvmPackagePartProvider(environment)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -105,24 +100,25 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) {
|
|||||||
return doAnalyze(psiFile)
|
return doAnalyze(psiFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doAnalyze(psiFile: KtFile): ReplLineAnalysisResult {
|
private fun doAnalyze(linePsi: KtFile): ReplLineAnalysisResult {
|
||||||
scriptDeclarationFactory.setDelegateFactory(FileBasedDeclarationProviderFactory(resolveSession.storageManager, listOf(psiFile)))
|
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) {
|
if (trace.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, linePsi) == null) {
|
||||||
trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile, resolveSession.getPackageFragment(FqName.ROOT))
|
trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, linePsi, resolveSession.getPackageFragment(FqName.ROOT))
|
||||||
}
|
}
|
||||||
|
|
||||||
val diagnostics = trace.bindingContext.diagnostics
|
val diagnostics = trace.bindingContext.diagnostics
|
||||||
val hasErrors = diagnostics.any { it.severity == Severity.ERROR }
|
val hasErrors = diagnostics.any { it.severity == Severity.ERROR }
|
||||||
if (hasErrors) {
|
if (hasErrors) {
|
||||||
|
replState.lineFailure(linePsi)
|
||||||
return ReplLineAnalysisResult.WithErrors(diagnostics)
|
return ReplLineAnalysisResult.WithErrors(diagnostics)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val scriptDescriptor = context.scripts[psiFile.script]!!.apply {
|
val scriptDescriptor = context.scripts[linePsi.script]!!
|
||||||
lastLineScope = this.scopeForInitializerResolution
|
replState.lineSuccess(linePsi, scriptDescriptor)
|
||||||
}
|
|
||||||
return ReplLineAnalysisResult.Successful(scriptDescriptor, diagnostics)
|
return ReplLineAnalysisResult.Successful(scriptDescriptor, diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,20 +168,44 @@ class CliReplAnalyzerEngine(private val environment: KotlinCoreEnvironment) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReplLastLineScopeProvider {
|
class ReplState {
|
||||||
val lastLineScope: LexicalScope?
|
private val lines = hashMapOf<KtFile, LineInfo>()
|
||||||
|
private val successfulLines = arrayListOf<SuccessfulLine>()
|
||||||
|
|
||||||
|
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(
|
class ReplFileScopeProvider(
|
||||||
private val lastLineScopeProvider: ReplLastLineScopeProvider,
|
private val replState: ReplState,
|
||||||
topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
private val fileScopeFactory: FileScopeFactory
|
||||||
storageManager: StorageManager,
|
) : FileScopeProvider {
|
||||||
moduleDescriptor: ModuleDescriptor,
|
override fun getFileResolutionScope(file: KtFile)
|
||||||
qualifiedExpressionResolver: QualifiedExpressionResolver,
|
= replState.lineInfo(file)?.lexicalScopeBeforeThisLine ?: fileScopeFactory.getLexicalScopeAndImportResolver(file).scope
|
||||||
bindingTrace: BindingTrace,
|
|
||||||
ktImportsFactory: KtImportsFactory
|
|
||||||
) : FileScopeProviderImpl(topLevelDescriptorProvider, storageManager, moduleDescriptor, qualifiedExpressionResolver, bindingTrace, ktImportsFactory) {
|
|
||||||
|
|
||||||
override fun getFileResolutionScope(file: KtFile): LexicalScope
|
override fun getImportResolver(file: KtFile) = fileScopeFactory.getLexicalScopeAndImportResolver(file).importResolver
|
||||||
= lastLineScopeProvider.lastLineScope ?: super.getFileResolutionScope(file)
|
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.cli.jvm.repl.di
|
|||||||
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.ReplFileScopeProvider
|
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.container.*
|
||||||
import org.jetbrains.kotlin.context.ModuleContext
|
import org.jetbrains.kotlin.context.ModuleContext
|
||||||
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
||||||
@@ -41,14 +41,14 @@ fun createContainerForReplWithJava(
|
|||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
declarationProviderFactory: DeclarationProviderFactory,
|
declarationProviderFactory: DeclarationProviderFactory,
|
||||||
moduleContentScope: GlobalSearchScope,
|
moduleContentScope: GlobalSearchScope,
|
||||||
lastLineScopeProvider: ReplLastLineScopeProvider,
|
replState: ReplState,
|
||||||
packagePartProvider: PackagePartProvider
|
packagePartProvider: PackagePartProvider
|
||||||
): ContainerForReplWithJava = createContainer("ReplWithJava") {
|
): ContainerForReplWithJava = createContainer("ReplWithJava") {
|
||||||
useInstance(packagePartProvider)
|
useInstance(packagePartProvider)
|
||||||
configureModule(moduleContext, JvmPlatform, bindingTrace)
|
configureModule(moduleContext, JvmPlatform, bindingTrace)
|
||||||
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project, LookupTracker.DO_NOTHING)
|
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project, LookupTracker.DO_NOTHING)
|
||||||
|
|
||||||
useInstance(lastLineScopeProvider)
|
useInstance(replState)
|
||||||
useImpl<ReplFileScopeProvider>()
|
useImpl<ReplFileScopeProvider>()
|
||||||
useInstance(declarationProviderFactory)
|
useInstance(declarationProviderFactory)
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -125,6 +125,7 @@ fun createContainerForLazyResolve(
|
|||||||
useInstance(declarationProviderFactory)
|
useInstance(declarationProviderFactory)
|
||||||
useInstance(LookupTracker.DO_NOTHING)
|
useInstance(LookupTracker.DO_NOTHING)
|
||||||
|
|
||||||
|
useImpl<FileScopeProviderImpl>()
|
||||||
targetEnvironment.configure(this)
|
targetEnvironment.configure(this)
|
||||||
|
|
||||||
useImpl<LazyResolveToken>()
|
useImpl<LazyResolveToken>()
|
||||||
|
|||||||
@@ -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<FqName>,
|
||||||
|
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<PropertyDescriptor> {
|
||||||
|
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<FunctionDescriptor> {
|
||||||
|
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<DeclarationDescriptor> {
|
||||||
|
// 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 <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): Name {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,205 +16,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.lazy
|
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.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.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(
|
class FileScopeProviderImpl(private val fileScopeFactory: FileScopeFactory) : FileScopeProvider {
|
||||||
private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
override fun getFileResolutionScope(file: KtFile): LexicalScope {
|
||||||
private val storageManager: StorageManager,
|
return fileScopeFactory.getLexicalScopeAndImportResolver(file).scope
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileData(val scope: LexicalScope, val importResolver: ImportResolver)
|
override fun getImportResolver(file: KtFile): ImportResolver {
|
||||||
|
return fileScopeFactory.getLexicalScopeAndImportResolver(file).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)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private enum class FilteringKind {
|
|
||||||
VISIBLE_CLASSES, INVISIBLE_CLASSES
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun currentPackageScope(
|
|
||||||
packageView: PackageViewDescriptor,
|
|
||||||
aliasImportNames: Collection<FqName>,
|
|
||||||
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<PropertyDescriptor> {
|
|
||||||
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<FunctionDescriptor> {
|
|
||||||
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<DeclarationDescriptor> {
|
|
||||||
// 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 <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getName(): Name {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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.LazyAnnotations;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationsContextImpl;
|
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationsContextImpl;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor;
|
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.LexicalScope;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||||
import org.jetbrains.kotlin.storage.*;
|
import org.jetbrains.kotlin.storage.*;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -109,7 +109,7 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void setFileScopeProvider(@NotNull FileScopeProviderImpl fileScopeProvider) {
|
public void setFileScopeProvider(@NotNull FileScopeProvider fileScopeProvider) {
|
||||||
this.fileScopeProvider = fileScopeProvider;
|
this.fileScopeProvider = fileScopeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user