From b7c774b9e53e0e6eab76e5c41429bb75f773e029 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Wed, 8 Nov 2023 19:47:27 +0900 Subject: [PATCH] [Analysis API] Generify 'KtCodeFragmentModule' to support ordinary files This commit introduces dangling file modules, which may be either code fragments or ordinary Kotlin files. As before, code fragments are analyzed against some context element, however ordinary files only have a context module. Code fragments can also have a dangling file module as a contextual one, including other code fragment. This is done to support potential usages in completion, intentions and refactorings. --- .../fir/components/KtFirCompilerFacility.kt | 4 +- .../structure/KtStaticModuleProvider.kt | 4 +- .../level/api/fir/LLFirResolveStateService.kt | 19 ++++----- ...DanglingFileDependenciesSymbolProvider.kt} | 2 +- .../sessions/LLFirAbstractSessionFactory.kt | 26 ++++++------- .../fir/sessions/LLFirCommonSessionFactory.kt | 6 +-- ...Session.kt => LLFirDanglingFileSession.kt} | 6 +-- .../api/fir/sessions/LLFirJsSessionFactory.kt | 6 +-- .../fir/sessions/LLFirJvmSessionFactory.kt | 12 +++--- .../fir/sessions/LLFirNativeSessionFactory.kt | 6 +-- .../api/fir/sessions/LLFirSessionCache.kt | 22 +++++------ .../LLFirSessionInvalidationService.kt | 8 ++-- .../state/LLFirResolvableResolveSession.kt | 11 ++++-- .../analysis/project/structure/KtModule.kt | 21 ++++++---- ...uleImpl.kt => KtDanglingFileModuleImpl.kt} | 39 ++++++++++++------- .../symbol/SymbolKotlinAsJavaSupport.kt | 11 ++++-- 16 files changed, 111 insertions(+), 92 deletions(-) rename analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/{LLFirCodeFragmentDependenciesSymbolProvider.kt => LLFirDanglingFileDependenciesSymbolProvider.kt} (98%) rename analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/{LLFirCodeFragmentSession.kt => LLFirDanglingFileSession.kt} (78%) rename analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/impl/{KtCodeFragmentModuleImpl.kt => KtDanglingFileModuleImpl.kt} (60%) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt index cf318cd8fb5..6b49c323d10 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirMo import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession import org.jetbrains.kotlin.analysis.low.level.api.fir.util.codeFragment -import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule +import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig @@ -248,7 +248,7 @@ internal class KtFirCompilerFacility( private fun computeTargetModules(module: KtModule): List { return when (module) { - is KtCodeFragmentModule -> listOf(module.contextModule, module) + is KtDanglingFileModule -> listOf(module.contextModule, module) else -> listOf(module) } } diff --git a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt index d2abf2ab7b1..670133a8504 100644 --- a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt +++ b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.analysis.api.standalone.base.project.structure import com.intellij.psi.PsiElement import com.intellij.psi.PsiFileSystemItem import org.jetbrains.kotlin.analysis.project.structure.* -import org.jetbrains.kotlin.analysis.project.structure.impl.KtCodeFragmentModuleImpl +import org.jetbrains.kotlin.analysis.project.structure.impl.KtDanglingFileModuleImpl import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.psiUtil.contains @@ -31,7 +31,7 @@ class KtStaticModuleProvider( .withAttachment("codeFragment.kt", containingPsiFile.text) val contextModule = getModule(contextElement, contextualModule) - return KtCodeFragmentModuleImpl(containingPsiFile, contextModule) + return KtDanglingFileModuleImpl(containingPsiFile, contextModule) } val containingVirtualFile = containingPsiFile.virtualFile diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt index 42113fc27fc..366f88d7999 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt @@ -54,15 +54,10 @@ class LLFirResolveSessionService(project: Project) { is KtSourceModule -> LLSourceModuleResolutionStrategyProvider is KtLibraryModule, is KtLibrarySourceModule -> LLLibraryModuleResolutionStrategyProvider(module) is KtScriptModule -> LLScriptModuleResolutionStrategyProvider(module) - is KtCodeFragmentModule -> { - val contextElement = module.codeFragment.context - if (contextElement != null) { - val contextModule = moduleProvider.getModule(contextElement) - val contextResolutionStrategyProvider = createResolutionStrategyProvider(contextModule, moduleProvider) - LLCodeFragmentResolutionStrategyProvider(contextResolutionStrategyProvider) - } else { - LLSimpleResolutionStrategyProvider(module) - } + is KtDanglingFileModule -> { + val contextModule = module.contextModule + val contextResolutionStrategyProvider = createResolutionStrategyProvider(contextModule, moduleProvider) + LLDanglingFileResolutionStrategyProvider(contextResolutionStrategyProvider) } is KtNotUnderContentRootModule -> LLSimpleResolutionStrategyProvider(module) else -> { @@ -77,7 +72,7 @@ class LLFirResolveSessionService(project: Project) { return when (moduleProvider.useSiteModule) { is KtSourceModule, is KtScriptModule, - is KtCodeFragmentModule -> LLSourceDiagnosticProvider(moduleProvider, sessionProvider) + is KtDanglingFileModule -> LLSourceDiagnosticProvider(moduleProvider, sessionProvider) else -> LLEmptyDiagnosticProvider } } @@ -115,10 +110,10 @@ private class LLScriptModuleResolutionStrategyProvider(private val useSiteModule } } -private class LLCodeFragmentResolutionStrategyProvider(private val delegate: LLModuleResolutionStrategyProvider) : LLModuleResolutionStrategyProvider { +private class LLDanglingFileResolutionStrategyProvider(private val delegate: LLModuleResolutionStrategyProvider) : LLModuleResolutionStrategyProvider { override fun getKind(module: KtModule): LLModuleResolutionStrategy { return when (module) { - is KtCodeFragmentModule -> LLModuleResolutionStrategy.LAZY + is KtDanglingFileModule -> LLModuleResolutionStrategy.LAZY else -> delegate.getKind(module) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCodeFragmentDependenciesSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirDanglingFileDependenciesSymbolProvider.kt similarity index 98% rename from analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCodeFragmentDependenciesSymbolProvider.kt rename to analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirDanglingFileDependenciesSymbolProvider.kt index fde8a990fce..e89f5c1bda2 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCodeFragmentDependenciesSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirDanglingFileDependenciesSymbolProvider.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile -class LLFirCodeFragmentDependenciesSymbolProvider(private val delegate: FirSymbolProvider) : FirSymbolProvider(delegate.session) { +class LLFirDanglingFileDependenciesSymbolProvider(private val delegate: FirSymbolProvider) : FirSymbolProvider(delegate.session) { override val symbolNamesProvider: FirSymbolNamesProvider get() = delegate.symbolNamesProvider diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt index cf9c918b537..e90a9e74702 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt @@ -44,8 +44,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirDummyCompilerLazyDeclara import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.session.* import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver -import org.jetbrains.kotlin.platform.has -import org.jetbrains.kotlin.platform.jvm.JvmPlatform import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver @@ -461,12 +459,12 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje } } - abstract fun createCodeFragmentSession(module: KtCodeFragmentModule, contextSession: LLFirSession): LLFirSession + abstract fun createDanglingFileSession(module: KtDanglingFileModule, contextSession: LLFirSession): LLFirSession - protected fun doCreateCodeFragmentSession( - module: KtCodeFragmentModule, + protected fun doCreateDanglingFileSession( + module: KtDanglingFileModule, contextSession: LLFirSession, - additionalSessionConfiguration: context(CodeFragmentSessionCreationContext) LLFirCodeFragmentSession.() -> Unit, + additionalSessionConfiguration: context(DanglingFileSessionCreationContext) LLFirDanglingFileSession.() -> Unit, ): LLFirSession { val platform = module.platform val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) @@ -475,7 +473,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) - val session = LLFirCodeFragmentSession(module, components, builtinsSession.builtinTypes) + val session = LLFirDanglingFileSession(module, components, builtinsSession.builtinTypes) components.session = session val moduleData = createModuleData(session) @@ -492,9 +490,8 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje this, components, canContainKotlinPackage = true, - ) { scope -> - scope.createScopedDeclarationProviderForFile(module.codeFragment) - } + declarationProviderFactory = { scope -> scope.createScopedDeclarationProviderForFile(module.file) } + ) register(FirProvider::class, firProvider) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) @@ -518,7 +515,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje } // Wrap dependencies into a single classpath-filtering provider - listOf(LLFirCodeFragmentDependenciesSymbolProvider(FirCompositeSymbolProvider(session, providers))) + listOf(LLFirDanglingFileDependenciesSymbolProvider(FirCompositeSymbolProvider(session, providers))) } register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider) @@ -535,7 +532,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje .createIfNeeded(this) ?.also { register(FirSwitchableExtensionDeclarationsSymbolProvider::class, it) } - val context = CodeFragmentSessionCreationContext( + val context = DanglingFileSessionCreationContext( moduleData, firProvider, dependencyProvider, @@ -547,7 +544,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje } } - protected class CodeFragmentSessionCreationContext( + protected class DanglingFileSessionCreationContext( val moduleData: LLFirModuleData, val firProvider: LLFirProvider, val dependencyProvider: LLFirDependenciesSymbolProvider, @@ -579,11 +576,10 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje fun getOrCreateSessionForDependency(dependency: KtModule): LLFirSession? = when (dependency) { is KtBuiltinsModule -> null // Built-ins are already added is KtBinaryModule -> llFirSessionCache.getSession(dependency, preferBinary = true) - is KtSourceModule -> llFirSessionCache.getSession(dependency) + is KtSourceModule, is KtDanglingFileModule -> llFirSessionCache.getSession(dependency) is KtScriptModule, is KtScriptDependencyModule, - is KtCodeFragmentModule, is KtNotUnderContentRootModule, is KtLibrarySourceModule, -> { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt index 847d1332a86..d4baadbfd7b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLi import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirModuleWithDependenciesSymbolProvider import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule -import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule +import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.providers.createPackagePartProvider @@ -74,8 +74,8 @@ internal class LLFirCommonSessionFactory(project: Project) : LLFirAbstractSessio } } - override fun createCodeFragmentSession(module: KtCodeFragmentModule, contextSession: LLFirSession): LLFirSession { - return doCreateCodeFragmentSession(module, contextSession) { + override fun createDanglingFileSession(module: KtDanglingFileModule, contextSession: LLFirSession): LLFirSession { + return doCreateDanglingFileSession(module, contextSession) { registerDefaultComponents() register( diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCodeFragmentSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirDanglingFileSession.kt similarity index 78% rename from analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCodeFragmentSession.kt rename to analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirDanglingFileSession.kt index 3f7ab226e5d..172d189115e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCodeFragmentSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirDanglingFileSession.kt @@ -6,12 +6,12 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents -import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule +import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.PrivateSessionConstructor -internal class LLFirCodeFragmentSession @PrivateSessionConstructor constructor( - ktModule: KtCodeFragmentModule, +internal class LLFirDanglingFileSession @PrivateSessionConstructor constructor( + ktModule: KtDanglingFileModule, override val moduleComponents: LLFirModuleResolveComponents, builtinTypes: BuiltinTypes, ) : LLFirResolvableModuleSession(ktModule, builtinTypes) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt index 1dd197aef77..420332251fb 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLi import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirModuleWithDependenciesSymbolProvider import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule -import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule +import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.fir.BuiltinTypes @@ -75,8 +75,8 @@ internal class LLFirJsSessionFactory(project: Project) : LLFirAbstractSessionFac } } - override fun createCodeFragmentSession(module: KtCodeFragmentModule, contextSession: LLFirSession): LLFirSession { - return doCreateCodeFragmentSession(module, contextSession) { + override fun createDanglingFileSession(module: KtDanglingFileModule, contextSession: LLFirSession): LLFirSession { + return doCreateDanglingFileSession(module, contextSession) { registerDefaultComponents() registerModuleIndependentJsComponents() diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt index 82f308481b3..d91c1208711 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt @@ -78,12 +78,14 @@ internal class LLFirJvmSessionFactory(project: Project) : LLFirAbstractSessionFa } } - override fun createCodeFragmentSession(module: KtCodeFragmentModule, contextSession: LLFirSession): LLFirSession { - return doCreateCodeFragmentSession(module, contextSession) { + override fun createDanglingFileSession(module: KtDanglingFileModule, contextSession: LLFirSession): LLFirSession { + return doCreateDanglingFileSession(module, contextSession) { registerJavaComponents(JavaModuleResolver.getInstance(project)) - val javaSymbolProvider = LLFirJavaSymbolProvider(this, moduleData, project, firProvider.searchScope) - register(JavaSymbolProvider::class, javaSymbolProvider) + val contextJavaSymbolProvider = contextSession.nullableJavaSymbolProvider + if (contextJavaSymbolProvider != null) { + register(JavaSymbolProvider::class, contextJavaSymbolProvider) + } register( FirSymbolProvider::class, @@ -93,7 +95,7 @@ internal class LLFirJvmSessionFactory(project: Project) : LLFirAbstractSessionFa firProvider.symbolProvider, switchableExtensionDeclarationsSymbolProvider, syntheticFunctionInterfaceProvider, - javaSymbolProvider + contextJavaSymbolProvider ), dependencyProvider ) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt index a096a7779e2..3dac1ee219f 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLi import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirModuleWithDependenciesSymbolProvider import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule -import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule +import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.providers.createPackagePartProvider @@ -72,8 +72,8 @@ internal class LLFirNativeSessionFactory(project: Project) : LLFirAbstractSessio } } - override fun createCodeFragmentSession(module: KtCodeFragmentModule, contextSession: LLFirSession): LLFirSession { - return doCreateCodeFragmentSession(module, contextSession) { + override fun createDanglingFileSession(module: KtDanglingFileModule, contextSession: LLFirSession): LLFirSession { + return doCreateDanglingFileSession(module, contextSession) { registerModuleIndependentNativeComponents() register( diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionCache.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionCache.kt index 3c19ac6cb95..fae96d9438c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionCache.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionCache.kt @@ -35,7 +35,7 @@ class LLFirSessionCache(private val project: Project) { private val sourceCache: SessionStorage = CollectionFactory.createConcurrentSoftValueMap() private val binaryCache: SessionStorage = CollectionFactory.createConcurrentSoftValueMap() - private val codeFragmentSessionCache: SessionStorage = CollectionFactory.createConcurrentSoftValueMap() + private val danglingFileSessionCache: SessionStorage = CollectionFactory.createConcurrentSoftValueMap() /** * Returns the existing session if found, or creates a new session and caches it. @@ -49,7 +49,7 @@ class LLFirSessionCache(private val project: Project) { } val targetCache = when (module) { - is KtCodeFragmentModule -> codeFragmentSessionCache + is KtDanglingFileModule -> danglingFileSessionCache else -> sourceCache } @@ -86,9 +86,9 @@ class LLFirSessionCache(private val project: Project) { val didSourceSessionExist = removeSessionFrom(module, sourceCache) val didBinarySessionExist = module is KtBinaryModule && removeSessionFrom(module, binaryCache) - val didCodeFragmentSessionExist = module is KtCodeFragmentModule && removeSessionFrom(module, codeFragmentSessionCache) + val didDanglingFileSessionExist = module is KtDanglingFileModule && removeSessionFrom(module, danglingFileSessionCache) - return didSourceSessionExist || didBinarySessionExist || didCodeFragmentSessionExist + return didSourceSessionExist || didBinarySessionExist || didDanglingFileSessionExist } private fun removeSessionFrom(module: KtModule, storage: SessionStorage): Boolean { @@ -114,11 +114,11 @@ class LLFirSessionCache(private val project: Project) { removeAllMatchingSessionsFrom(sourceCache) { it !is KtBinaryModule && it !is KtLibrarySourceModule } } - removeAllCodeFragmentSessions() + removeAllDanglingFileSessions() } - fun removeAllCodeFragmentSessions() { - removeAllSessionsFrom(codeFragmentSessionCache) + fun removeAllDanglingFileSessions() { + removeAllSessionsFrom(danglingFileSessionCache) } // Removing script sessions is only needed temporarily until KTIJ-25620 has been implemented. @@ -159,11 +159,11 @@ class LLFirSessionCache(private val project: Project) { is KtLibraryModule, is KtLibrarySourceModule -> sessionFactory.createLibrarySession(module) is KtSdkModule -> sessionFactory.createBinaryLibrarySession(module) is KtScriptModule -> sessionFactory.createScriptSession(module) - is KtCodeFragmentModule -> { - // 'KtCodeFragment' context must have an analyzable session, so we can properly compile code against it. - // 'KtCodeFragmentModule' is always a leaf module, there might not be a circular reference. + is KtDanglingFileModule -> { + // Dangling file context must have an analyzable session, so we can properly compile code against it. + // 'KtDanglingFileModule' is always a leaf module, so there might not be a circular reference. val contextSession = getSession(module.contextModule, preferBinary = false) - sessionFactory.createCodeFragmentSession(module, contextSession) + sessionFactory.createDanglingFileSession(module, contextSession) } is KtNotUnderContentRootModule -> sessionFactory.createNotUnderContentRootResolvableSession(module) else -> error("Unexpected module kind: ${module::class.simpleName}") diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt index 0ccd19d2bd5..cc446141668 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt @@ -54,7 +54,7 @@ class LLFirSessionInvalidationService(private val project: Project) : Disposable ) busConnection.subscribe( PsiModificationTracker.TOPIC, - PsiModificationTracker.Listener { invalidateAllCodeFragments() } + PsiModificationTracker.Listener { invalidateAllDanglingFiles() } ) } @@ -85,7 +85,7 @@ class LLFirSessionInvalidationService(private val project: Project) : Disposable sessionCache.removeAllScriptSessions() } - sessionCache.removeAllCodeFragmentSessions() + sessionCache.removeAllDanglingFileSessions() } private fun invalidateAll(includeLibraryModules: Boolean) { @@ -105,8 +105,8 @@ class LLFirSessionInvalidationService(private val project: Project) : Disposable LLFirSessionCache.getInstance(project).removeAllSessions(includeLibraryModules) } - private fun invalidateAllCodeFragments() { - LLFirSessionCache.getInstance(project).removeAllCodeFragmentSessions() + private fun invalidateAllDanglingFiles() { + LLFirSessionCache.getInstance(project).removeAllDanglingFileSessions() } override fun dispose() { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt index 44c4e941da7..1933669c03a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt @@ -63,9 +63,10 @@ internal class LLFirResolvableResolveSession( phase: FirResolvePhase, ): FirBasedSymbol<*> { val containingKtFile = ktDeclaration.containingKtFile - val module = getModule(containingKtFile.originalKtFile ?: containingKtFile) + val module = getModule(containingKtFile) + return when (getModuleResolutionStrategy(module)) { - LLModuleResolutionStrategy.LAZY -> findSourceFirSymbol(ktDeclaration, module).also { resolveFirToPhase(it.fir, phase) } + LLModuleResolutionStrategy.LAZY -> findSourceFirSymbol(ktDeclaration).also { resolveFirToPhase(it.fir, phase) } LLModuleResolutionStrategy.STATIC -> findFirCompiledSymbol(ktDeclaration, module) } } @@ -81,8 +82,10 @@ internal class LLFirResolvableResolveSession( return firDeclaration.symbol } - private fun findSourceFirSymbol(ktDeclaration: KtDeclaration, module: KtModule): FirBasedSymbol<*> { - return findSourceFirDeclarationByDeclaration(ktDeclaration.originalDeclaration ?: ktDeclaration, module) + private fun findSourceFirSymbol(ktDeclaration: KtDeclaration): FirBasedSymbol<*> { + val targetDeclaration = ktDeclaration.originalDeclaration ?: ktDeclaration + val targetModule = getModule(targetDeclaration) + return findSourceFirDeclarationByDeclaration(targetDeclaration, targetModule) } private fun findSourceFirDeclarationByDeclaration(ktDeclaration: KtDeclaration, module: KtModule): FirBasedSymbol<*> { diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt index 5a753fc9202..97aaef3bfe3 100644 --- a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt @@ -10,7 +10,6 @@ import com.intellij.psi.PsiFile import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import java.nio.file.Path @@ -216,21 +215,29 @@ public interface KtScriptDependencyModule : KtModule { } /** - * A module for a Kotlin code fragment – a piece of code analyzed against a specific context element. + * A module for a dangling file. Such files are usually temporary and are stored in-memory. + * Dangling files may be created for various purposes, such as: a code fragment for the evaluator, a sandbox for testing code modification + * applicability, etc. */ -public interface KtCodeFragmentModule : KtModule { +public interface KtDanglingFileModule : KtModule { /** - * A code fragment PSI. + * A temporary file PSI. */ - public val codeFragment: KtCodeFragment + public val file: KtFile /** - * Module of the context element. + * The module against which the [file] is analyzed. */ public val contextModule: KtModule + /** + * True if the [file] is a code fragment. + * Useful to recognize code fragments when their PSI was collected. + */ + public val isCodeFragment: Boolean + override val moduleDescription: String - get() = "Code fragment" + get() = "Temporary file" } /** diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtCodeFragmentModuleImpl.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtDanglingFileModuleImpl.kt similarity index 60% rename from analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtCodeFragmentModuleImpl.kt rename to analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtDanglingFileModuleImpl.kt index 392609a31d0..4e4a576d301 100644 --- a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtCodeFragmentModuleImpl.kt +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtDanglingFileModuleImpl.kt @@ -7,22 +7,35 @@ package org.jetbrains.kotlin.analysis.project.structure.impl import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.psi.KtCodeFragment +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import java.util.Objects -public class KtCodeFragmentModuleImpl( - codeFragment: KtCodeFragment, +public class KtDanglingFileModuleImpl( + file: KtFile, override val contextModule: KtModule -) : KtCodeFragmentModule { - private val codeFragmentRef = codeFragment.createSmartPointer() +) : KtDanglingFileModule { + override val isCodeFragment: Boolean = file is KtCodeFragment - override val codeFragment: KtCodeFragment - get() = codeFragmentRef.element?.takeIf { it.isValid } ?: error("Code fragment module is invalid") + private val fileRef = file.createSmartPointer() + + init { + require(contextModule != this) + + if (contextModule is KtDanglingFileModule) { + // Only code fragments can depend on dangling files. + // This is needed for completion, inspections and refactorings. + require(file is KtCodeFragment) + } + } + + override val file: KtFile + get() = fileRef.element?.takeIf { it.isValid } ?: error("Dangling file module is invalid") override val project: Project get() = contextModule.project @@ -34,7 +47,7 @@ public class KtCodeFragmentModuleImpl( get() = contextModule.analyzerServices override val contentScope: GlobalSearchScope - get() = GlobalSearchScope.fileScope(codeFragment) + get() = GlobalSearchScope.fileScope(file) override val directRegularDependencies: List get() = contextModule.directRegularDependencies @@ -51,16 +64,16 @@ public class KtCodeFragmentModuleImpl( override fun equals(other: Any?): Boolean { if (this === other) return true - if (other is KtCodeFragmentModuleImpl) { - val selfCodeFragment = this.codeFragmentRef.element - val otherCodeFragment = other.codeFragmentRef.element - return selfCodeFragment != null && selfCodeFragment == otherCodeFragment && contextModule == other.contextModule + if (other is KtDanglingFileModuleImpl) { + val selfFile = this.fileRef.element + val otherFile = other.fileRef.element + return selfFile != null && selfFile == otherFile && contextModule == other.contextModule } return false } override fun hashCode(): Int { - return Objects.hash(codeFragmentRef.element, contextModule) + return Objects.hash(fileRef.element, contextModule) } } \ No newline at end of file diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/SymbolKotlinAsJavaSupport.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/SymbolKotlinAsJavaSupport.kt index 26af12ed7a0..6aba20066d3 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/SymbolKotlinAsJavaSupport.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/SymbolKotlinAsJavaSupport.kt @@ -194,10 +194,13 @@ class SymbolKotlinAsJavaSupport(project: Project) : KotlinAsJavaSupportBase true - is KtLibraryModule -> true - else -> false + private fun KtModule.isFromSourceOrLibraryBinary(): Boolean { + return when (this) { + is KtSourceModule -> true + is KtLibraryModule -> true + is KtDanglingFileModule -> contextModule.isFromSourceOrLibraryBinary() + else -> false + } } }