[Analysis API] implement API to extend Kotlin resolution by generated declarations
^KT-57930 fixed
This commit is contained in:
committed by
Space Team
parent
0dbc948616
commit
d68587de77
+38
-3
@@ -5,12 +5,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.api.impl.base.components
|
package org.jetbrains.kotlin.analysis.api.impl.base.components
|
||||||
|
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.analysis.api.components.KtAnalysisScopeProvider
|
import org.jetbrains.kotlin.analysis.api.components.KtAnalysisScopeProvider
|
||||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.allDirectDependencies
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.analysisExtensionFileContextModule
|
||||||
import org.jetbrains.kotlin.analysis.providers.KotlinResolutionScopeProvider
|
import org.jetbrains.kotlin.analysis.providers.KotlinResolutionScopeProvider
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.contains
|
import org.jetbrains.kotlin.psi.psiUtil.contains
|
||||||
|
|
||||||
class KtAnalysisScopeProviderImpl(
|
class KtAnalysisScopeProviderImpl(
|
||||||
@@ -18,13 +26,40 @@ class KtAnalysisScopeProviderImpl(
|
|||||||
override val token: KtLifetimeToken
|
override val token: KtLifetimeToken
|
||||||
) : KtAnalysisScopeProvider() {
|
) : KtAnalysisScopeProvider() {
|
||||||
|
|
||||||
private val scope by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
private val baseResolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
KotlinResolutionScopeProvider.getInstance(analysisSession.useSiteModule.project).getResolutionScope(analysisSession.useSiteModule)
|
KotlinResolutionScopeProvider.getInstance(analysisSession.useSiteModule.project).getResolutionScope(analysisSession.useSiteModule)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAnalysisScope(): GlobalSearchScope = scope
|
private val resolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
|
KtAnalysisScopeProviderResolveScope(baseResolveScope, analysisSession.useSiteModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAnalysisScope(): GlobalSearchScope = resolveScope
|
||||||
|
|
||||||
override fun canBeAnalysed(psi: PsiElement): Boolean {
|
override fun canBeAnalysed(psi: PsiElement): Boolean {
|
||||||
return scope.contains(psi)
|
return baseResolveScope.contains(psi)
|
||||||
|
|| psi.isFromGeneratedModule()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.isFromGeneratedModule(): Boolean {
|
||||||
|
val ktFile = containingFile as? KtFile ?: return false
|
||||||
|
return ktFile.virtualFile?.isFromGeneratedModule(analysisSession.useSiteModule) == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class KtAnalysisScopeProviderResolveScope(
|
||||||
|
private val base: GlobalSearchScope,
|
||||||
|
private val useSiteModule: KtModule
|
||||||
|
) : GlobalSearchScope() {
|
||||||
|
override fun getProject(): Project? = base.project
|
||||||
|
override fun isSearchInModuleContent(aModule: Module): Boolean = base.isSearchInModuleContent(aModule)
|
||||||
|
override fun isSearchInLibraries(): Boolean = base.isSearchInLibraries
|
||||||
|
override fun contains(file: VirtualFile): Boolean = base.contains(file) || file.isFromGeneratedModule(useSiteModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(KtModuleStructureInternals::class)
|
||||||
|
private fun VirtualFile.isFromGeneratedModule(useSiteModule: KtModule): Boolean {
|
||||||
|
val analysisContextModule = analysisExtensionFileContextModule ?: return false
|
||||||
|
if (analysisContextModule == useSiteModule) return true
|
||||||
|
return analysisContextModule in useSiteModule.allDirectDependencies()
|
||||||
|
}
|
||||||
|
|||||||
+4
@@ -14,6 +14,8 @@ class KtStaticModuleProvider(
|
|||||||
private val builtinsModule: KtBuiltinsModule,
|
private val builtinsModule: KtBuiltinsModule,
|
||||||
val projectStructure: KtModuleProjectStructure,
|
val projectStructure: KtModuleProjectStructure,
|
||||||
) : ProjectStructureProvider() {
|
) : ProjectStructureProvider() {
|
||||||
|
|
||||||
|
@OptIn(KtModuleStructureInternals::class)
|
||||||
override fun getKtModuleForKtElement(element: PsiElement): KtModule {
|
override fun getKtModuleForKtElement(element: PsiElement): KtModule {
|
||||||
val containingFileAsPsiFile = element.containingFile
|
val containingFileAsPsiFile = element.containingFile
|
||||||
val containingFileAsVirtualFile = containingFileAsPsiFile.virtualFile
|
val containingFileAsVirtualFile = containingFileAsPsiFile.virtualFile
|
||||||
@@ -21,6 +23,8 @@ class KtStaticModuleProvider(
|
|||||||
return builtinsModule
|
return builtinsModule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
containingFileAsVirtualFile.analysisExtensionFileContextModule?.let { return it }
|
||||||
|
|
||||||
return projectStructure.mainModules
|
return projectStructure.mainModules
|
||||||
.first { module ->
|
.first { module ->
|
||||||
element in module.ktModule.contentScope
|
element in module.ktModule.contentScope
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.api.resolve.extensions
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.ModificationTracker
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a list of Kotlin files which provides additional, generated declarations for resolution.
|
||||||
|
*
|
||||||
|
* Provided by the [KtResolveExtensionProvider].
|
||||||
|
*
|
||||||
|
* All member implementations should:
|
||||||
|
* - consider caching the results for subsequent invocations.
|
||||||
|
* - be lightweight and not build the whole file structure inside.
|
||||||
|
* - not use the Kotlin resolve inside, as this function is called during session initialization, so Analysis API access is forbidden.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
* @see KtResolveExtensionProvider
|
||||||
|
*/
|
||||||
|
abstract class KtResolveExtension {
|
||||||
|
/**
|
||||||
|
* Get the list of files that should be generated for the module.
|
||||||
|
*
|
||||||
|
* The content of those files should remain valid until the tracker [getModificationTracker] is modified.
|
||||||
|
*
|
||||||
|
* Returned files should contain a valid Kotlin code.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
* @see KtResolveExtension
|
||||||
|
*/
|
||||||
|
abstract fun getKtFiles(): List<KtResolveExtensionFile>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a [ModificationTracker], which controls the validity lifecycle of the files provided by [getKtFiles].
|
||||||
|
*
|
||||||
|
* All files generated by [getKtFiles] should be valid if the [ModificationTracker] did not change.
|
||||||
|
* If files become invalid (e.g., the in-source declarations they were based on changed) the [ModificationTracker] should be incremented.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtension
|
||||||
|
*/
|
||||||
|
abstract fun getModificationTracker(): ModificationTracker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of packages that are contained in the files provided by [getKtFiles].
|
||||||
|
*
|
||||||
|
* The returned package set should be a strict set of all file packages,
|
||||||
|
* so `for-all pckg: pckg in getContainedPackages() <=> exists file: file in getKtFiles() && file.getFilePackageName() == pckg`
|
||||||
|
*
|
||||||
|
* @see KtResolveExtension
|
||||||
|
*/
|
||||||
|
abstract fun getContainedPackages(): Set<FqName>
|
||||||
|
}
|
||||||
+87
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.api.resolve.extensions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the Kotlin file which provides additional, generated declarations for resolution.
|
||||||
|
*
|
||||||
|
* All member implementations should:
|
||||||
|
* - consider caching the results for subsequent invocations.
|
||||||
|
* - be lightweight and not build the whole file structure inside.
|
||||||
|
* - not use the Kotlin resolve inside, as this function is called during session initialization, so Analysis API access is forbidden.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtension
|
||||||
|
*/
|
||||||
|
abstract class KtResolveExtensionFile {
|
||||||
|
/**
|
||||||
|
* The name a Kotlin file which will be generated.
|
||||||
|
*
|
||||||
|
* Should have the `.kt` extension.
|
||||||
|
*
|
||||||
|
* It will be used as a Java facade name, e.g., for the file name `myFile.kt`, the `MyFileKt` facade is generated if the file contains some properties or functions.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
*/
|
||||||
|
abstract fun getFileName(): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [FqName] of the package specified in the file
|
||||||
|
*
|
||||||
|
* The operation might be called regularly, so the [getFilePackageName] should work fast and avoid building the whole file text.
|
||||||
|
*
|
||||||
|
* It should be equal to the package name specified in the [buildFileText].
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
*/
|
||||||
|
abstract fun getFilePackageName(): FqName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of top-level classifier (classes, interfaces, objects, and type-aliases) names in the file.
|
||||||
|
*
|
||||||
|
* The result may have false-positive entries but cannot have false-negative entries. It should contain all the names in the package but may have some additional names that are not there.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
*/
|
||||||
|
abstract fun getTopLevelClassifierNames(): Set<Name>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of top-level callable (functions and properties) names in the file.
|
||||||
|
*
|
||||||
|
* The result may have false-positive entries but cannot have false-negative entries. It should contain all the names in the package but may have some additional names that are not there.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
*/
|
||||||
|
abstract fun getTopLevelCallableNames(): Set<Name>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the generated Kotlin source file text.
|
||||||
|
*
|
||||||
|
* The resulted String should be a valid Kotlin code.
|
||||||
|
* It should be consistent with other declarations which are present in the [KtResolveExtensionFile], more specifically:
|
||||||
|
* 1. [getFilePackageName] should be equal to the file's package name.
|
||||||
|
* 2. All classifier names should be contained in the [getTopLevelClassifierNames].
|
||||||
|
* 3. All callable names should be contained in the [getTopLevelCallableNames].
|
||||||
|
*
|
||||||
|
* Additional restrictions on the file text:
|
||||||
|
* 1. The File should not contain the `kotlin.jvm.JvmMultifileClass` and `kotlin.jvm.JvmName` annotations on the file level.
|
||||||
|
* 2. All declaration types should be specified explicitly.
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
*/
|
||||||
|
abstract fun buildFileText(): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [KtResolveExtensionReferenceTargetsPsiProvider] for this [KtResolveExtensionFile].
|
||||||
|
*
|
||||||
|
* @see KtResolveExtensionReferenceTargetsPsiProvider
|
||||||
|
* @see KtResolveExtensionFile
|
||||||
|
*/
|
||||||
|
abstract fun createTargetPsiProvider(): KtResolveExtensionReferenceTargetsPsiProvider
|
||||||
|
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.api.resolve.extensions
|
||||||
|
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows extending Kotlin resolution by generating additional declarations.
|
||||||
|
*
|
||||||
|
* Those declarations will be analyzed the same way as they were just regular source files inside the project.
|
||||||
|
*
|
||||||
|
* All member implementations should consider caching the results for subsequent invocations.
|
||||||
|
*/
|
||||||
|
abstract class KtResolveExtensionProvider {
|
||||||
|
/**
|
||||||
|
* Provides a list of [KtResolveExtension]s for a given [KtModule].
|
||||||
|
*
|
||||||
|
* Should not perform any heavy analysis and the generation of the actual files. All file generation should be performed only in [KtResolveExtensionFile.buildFileText].
|
||||||
|
*
|
||||||
|
* Implementations should consider caching the results, so the subsequent invocations should be performed instantly.
|
||||||
|
*
|
||||||
|
* Implementation cannot use the Kotlin resolve inside, as this function is called during session initialization, so Analysis API access is forbidden.
|
||||||
|
*/
|
||||||
|
abstract fun provideExtensionsFor(module: KtModule): List<KtResolveExtension>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val EP_NAME = ExtensionPointName<KtResolveExtensionProvider>("org.jetbrains.kotlin.ktResolveExtensionProvider")
|
||||||
|
|
||||||
|
fun provideExtensionsFor(module: KtModule): List<KtResolveExtension> {
|
||||||
|
return EP_NAME.getExtensionList(module.project).flatMap { it.provideExtensionsFor(module) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ dependencies {
|
|||||||
implementation(project(":compiler:frontend.common"))
|
implementation(project(":compiler:frontend.common"))
|
||||||
implementation(project(":compiler:fir:entrypoint"))
|
implementation(project(":compiler:fir:entrypoint"))
|
||||||
implementation(project(":analysis:analysis-api-providers"))
|
implementation(project(":analysis:analysis-api-providers"))
|
||||||
|
implementation(project(":analysis:analysis-api"))
|
||||||
implementation(project(":analysis:analysis-internal-utils"))
|
implementation(project(":analysis:analysis-internal-utils"))
|
||||||
|
|
||||||
// We cannot use the latest version `3.1.5` because it doesn't support Java 8.
|
// We cannot use the latest version `3.1.5` because it doesn't support Java 8.
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.yieldIfNotNull
|
import org.jetbrains.kotlin.utils.yieldIfNotNull
|
||||||
|
|
||||||
internal class FileBasedKotlinDeclarationProvider(private val kotlinFile: KtFile) : KotlinDeclarationProvider() {
|
internal class FileBasedKotlinDeclarationProvider(val kotlinFile: KtFile) : KotlinDeclarationProvider() {
|
||||||
private val topLevelDeclarations: Sequence<KtDeclaration>
|
private val topLevelDeclarations: Sequence<KtDeclaration>
|
||||||
get() {
|
get() {
|
||||||
return sequence {
|
return sequence {
|
||||||
|
|||||||
+14
-1
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure
|
|||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.createSealedInheritorsProvider
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.createSealedInheritorsProvider
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches.FirThreadSafeCachesFactory
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches.FirThreadSafeCachesFactory
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdePredicateBasedProvider
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdePredicateBasedProvider
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdeRegisteredPluginAnnotations
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdeRegisteredPluginAnnotations
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirNonEmptyResolveExtensionTool
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirResolveExtensionTool
|
||||||
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.sessions.LLFirSourcesSession
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSourcesSession
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirExceptionHandler
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirExceptionHandler
|
||||||
@@ -42,8 +45,18 @@ internal fun LLFirSession.registerIdeComponents(project: Project) {
|
|||||||
register(FirCachesFactory::class, FirThreadSafeCachesFactory)
|
register(FirCachesFactory::class, FirThreadSafeCachesFactory)
|
||||||
register(SealedClassInheritorsProvider::class, project.createSealedInheritorsProvider())
|
register(SealedClassInheritorsProvider::class, project.createSealedInheritorsProvider())
|
||||||
register(FirExceptionHandler::class, LLFirExceptionHandler)
|
register(FirExceptionHandler::class, LLFirExceptionHandler)
|
||||||
|
createResolveExtensionTool()?.let {
|
||||||
|
register(LLFirResolveExtensionTool::class, it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun LLFirSession.createResolveExtensionTool(): LLFirResolveExtensionTool? {
|
||||||
|
val extensions = KtResolveExtensionProvider.provideExtensionsFor(ktModule)
|
||||||
|
if (extensions.isEmpty()) return null
|
||||||
|
return LLFirNonEmptyResolveExtensionTool(this, extensions)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal inline fun createCompositeSymbolProvider(
|
internal inline fun createCompositeSymbolProvider(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
createSubProviders: MutableList<FirSymbolProvider>.() -> Unit
|
createSubProviders: MutableList<FirSymbolProvider>.() -> Unit
|
||||||
@@ -52,7 +65,7 @@ internal inline fun createCompositeSymbolProvider(
|
|||||||
|
|
||||||
@SessionConfiguration
|
@SessionConfiguration
|
||||||
internal fun FirSession.registerCompilerPluginExtensions(project: Project, module: KtSourceModule) {
|
internal fun FirSession.registerCompilerPluginExtensions(project: Project, module: KtSourceModule) {
|
||||||
val extensionProvider = project.getService(KtCompilerPluginsProvider::class.java) ?: return
|
val extensionProvider = project.getService<KtCompilerPluginsProvider>(KtCompilerPluginsProvider::class.java) ?: return
|
||||||
FirSessionConfigurator(this).apply {
|
FirSessionConfigurator(this).apply {
|
||||||
val registrars = FirExtensionRegistrarAdapter.getInstances(project) +
|
val registrars = FirExtensionRegistrarAdapter.getInstances(project) +
|
||||||
extensionProvider.getRegisteredExtensions(module, FirExtensionRegistrarAdapter)
|
extensionProvider.getRegisteredExtensions(module, FirExtensionRegistrarAdapter)
|
||||||
|
|||||||
+28
-3
@@ -6,7 +6,12 @@
|
|||||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
|
package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
|
||||||
|
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBuilder
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBuilder
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.CompositeKotlinDeclarationProvider
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.CompositeKotlinPackageProvider
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirResolveExtensionTool
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.llResolveExtensionTool
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirCompositeSymbolProviderNameCache
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolProviderNameCache
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolProviderNameCache
|
||||||
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
|
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
|
||||||
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
|
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
|
||||||
@@ -32,10 +37,25 @@ import org.jetbrains.kotlin.psi.KtFile
|
|||||||
internal class LLFirProviderHelper(
|
internal class LLFirProviderHelper(
|
||||||
firSession: FirSession,
|
firSession: FirSession,
|
||||||
private val firFileBuilder: LLFirFileBuilder,
|
private val firFileBuilder: LLFirFileBuilder,
|
||||||
private val declarationProvider: KotlinDeclarationProvider,
|
mainDeclarationProvider: KotlinDeclarationProvider,
|
||||||
private val packageProvider: KotlinPackageProvider,
|
mainPackageProvider: KotlinPackageProvider,
|
||||||
canContainKotlinPackage: Boolean,
|
canContainKotlinPackage: Boolean,
|
||||||
) {
|
) {
|
||||||
|
private val extensionTool: LLFirResolveExtensionTool? = firSession.llResolveExtensionTool
|
||||||
|
|
||||||
|
private val declarationProvider = CompositeKotlinDeclarationProvider.create(
|
||||||
|
listOfNotNull(
|
||||||
|
mainDeclarationProvider,
|
||||||
|
extensionTool?.declarationProvider,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val packageProvider = CompositeKotlinPackageProvider.create(
|
||||||
|
listOfNotNull(
|
||||||
|
mainPackageProvider,
|
||||||
|
extensionTool?.packageProvider,
|
||||||
|
)
|
||||||
|
)
|
||||||
private val allowKotlinPackage = canContainKotlinPackage ||
|
private val allowKotlinPackage = canContainKotlinPackage ||
|
||||||
firSession.languageVersionSettings.getFlag(AnalysisFlags.allowKotlinPackage)
|
firSession.languageVersionSettings.getFlag(AnalysisFlags.allowKotlinPackage)
|
||||||
|
|
||||||
@@ -60,7 +80,12 @@ internal class LLFirProviderHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val symbolNameCache = LLFirKotlinSymbolProviderNameCache(firSession, declarationProvider)
|
val symbolNameCache = LLFirCompositeSymbolProviderNameCache.create(
|
||||||
|
listOfNotNull(
|
||||||
|
LLFirKotlinSymbolProviderNameCache(firSession, declarationProvider),
|
||||||
|
extensionTool?.symbolNameCache,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
fun getFirClassifierByFqNameAndDeclaration(
|
fun getFirClassifierByFqNameAndDeclaration(
|
||||||
classId: ClassId,
|
classId: ClassId,
|
||||||
|
|||||||
+276
@@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.ModificationTracker
|
||||||
|
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtension
|
||||||
|
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile
|
||||||
|
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionReferenceTargetsPsiProvider
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.FileBasedKotlinDeclarationProvider
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirSymbolProviderNameCache
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.analysisExtensionFileContextModule
|
||||||
|
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
|
||||||
|
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulate all the work with the [KtResolveExtension] for the LL API.
|
||||||
|
*
|
||||||
|
* Caches generated [KtResolveExtensionFile]s, creates [KotlinDeclarationProvider], [KotlinPackageProvider], [LLFirSymbolProviderNameCache] needed for the [org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider].
|
||||||
|
*/
|
||||||
|
internal abstract class LLFirResolveExtensionTool : FirSessionComponent {
|
||||||
|
abstract val modificationTrackers: List<ModificationTracker>
|
||||||
|
abstract val declarationProvider: KotlinDeclarationProvider
|
||||||
|
abstract val packageProvider: KotlinPackageProvider
|
||||||
|
abstract val symbolNameCache: LLFirSymbolProviderNameCache
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val FirSession.llResolveExtensionTool: LLFirResolveExtensionTool? by FirSession.nullableSessionComponentAccessor()
|
||||||
|
|
||||||
|
internal class LLFirNonEmptyResolveExtensionTool(
|
||||||
|
session: LLFirSession,
|
||||||
|
extensions: List<KtResolveExtension>,
|
||||||
|
) : LLFirResolveExtensionTool() {
|
||||||
|
init {
|
||||||
|
require(extensions.isNotEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
private val fileProvider = LLFirResolveExtensionsFileProvider(extensions)
|
||||||
|
|
||||||
|
private val packageFilter = LLFirResolveExtensionToolPackageFilter(extensions)
|
||||||
|
|
||||||
|
override val modificationTrackers by lazy { extensions.map { it.getModificationTracker() } }
|
||||||
|
|
||||||
|
override val declarationProvider: KotlinDeclarationProvider =
|
||||||
|
LLFirResolveExtensionToolDeclarationProvider(fileProvider, session.ktModule)
|
||||||
|
|
||||||
|
override val packageProvider: KotlinPackageProvider = LLFirResolveExtensionToolPackageProvider(packageFilter)
|
||||||
|
|
||||||
|
override val symbolNameCache: LLFirSymbolProviderNameCache = LLFirResolveExtensionToolNameCache(packageFilter, fileProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LLFirResolveExtensionToolNameCache(
|
||||||
|
private val packageFilter: LLFirResolveExtensionToolPackageFilter,
|
||||||
|
private val fileProvider: LLFirResolveExtensionsFileProvider,
|
||||||
|
) : LLFirSymbolProviderNameCache() {
|
||||||
|
override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String>? {
|
||||||
|
if (!packageFilter.packageExists(packageFqName)) return emptySet()
|
||||||
|
return fileProvider.getFilesByPackage(packageFqName)
|
||||||
|
.flatMap { it.getTopLevelClassifierNames() }
|
||||||
|
.mapTo(mutableSetOf()) { it.asString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> {
|
||||||
|
if (!packageFilter.packageExists(packageFqName)) return emptySet()
|
||||||
|
return fileProvider.getFilesByPackage(packageFqName)
|
||||||
|
.flatMapTo(mutableSetOf()) { it.getTopLevelCallableNames() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean {
|
||||||
|
if (!packageFilter.packageExists(classId.packageFqName)) return false
|
||||||
|
|
||||||
|
return fileProvider.getFilesByPackage(classId.packageFqName)
|
||||||
|
.any { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean {
|
||||||
|
if (!packageFilter.packageExists(packageFqName)) return false
|
||||||
|
|
||||||
|
return fileProvider.getFilesByPackage(packageFqName)
|
||||||
|
.any { it.mayHaveTopLevelCallable(name) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LLFirResolveExtensionToolPackageFilter(
|
||||||
|
private val extensions: List<KtResolveExtension>
|
||||||
|
) {
|
||||||
|
val allPackages: Set<FqName> by lazy {
|
||||||
|
extensions.flatMapTo(mutableSetOf()) { it.getContainedPackages() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageExists(packageFqName: FqName): Boolean {
|
||||||
|
return packageFqName in allPackages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LLFirResolveExtensionToolDeclarationProvider(
|
||||||
|
private val extensionProvider: LLFirResolveExtensionsFileProvider,
|
||||||
|
private val ktModule: KtModule,
|
||||||
|
) : KotlinDeclarationProvider() {
|
||||||
|
|
||||||
|
private val extensionFileToDeclarationProvider: ConcurrentHashMap<KtResolveExtensionFile, FileBasedKotlinDeclarationProvider> =
|
||||||
|
ConcurrentHashMap()
|
||||||
|
|
||||||
|
override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? {
|
||||||
|
return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
|
||||||
|
.firstNotNullOfOrNull { it.getClassLikeDeclarationByClassId(classId) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAllClassesByClassId(classId: ClassId): Collection<KtClassOrObject> {
|
||||||
|
return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
|
||||||
|
.flatMapTo(mutableListOf()) { it.getAllClassesByClassId(classId) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAllTypeAliasesByClassId(classId: ClassId): Collection<KtTypeAlias> {
|
||||||
|
return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
|
||||||
|
.flatMapTo(mutableListOf()) { it.getAllTypeAliasesByClassId(classId) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName): Set<Name> {
|
||||||
|
return getDeclarationProvidersByPackage(packageFqName) { true }
|
||||||
|
.flatMapTo(mutableSetOf()) { it.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty> {
|
||||||
|
return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) }
|
||||||
|
.flatMapTo(mutableListOf()) { it.getTopLevelProperties(callableId) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction> {
|
||||||
|
return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) }
|
||||||
|
.flatMapTo(mutableListOf()) { it.getTopLevelFunctions(callableId) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTopLevelCallableFiles(callableId: CallableId): Collection<KtFile> {
|
||||||
|
return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) }
|
||||||
|
.mapTo(mutableListOf()) { it.kotlinFile }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> {
|
||||||
|
return extensionProvider.getFilesByPackage(packageFqName).flatMapTo(mutableSetOf()) { it.getTopLevelClassifierNames() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findFilesForFacadeByPackage(packageFqName: FqName): Collection<KtFile> {
|
||||||
|
return getDeclarationProvidersByPackage(packageFqName) { file ->
|
||||||
|
file.getTopLevelCallableNames().isNotEmpty()
|
||||||
|
}.mapTo(mutableListOf()) { it.kotlinFile }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findFilesForFacade(facadeFqName: FqName): Collection<KtFile> {
|
||||||
|
if (facadeFqName.isRoot) return emptyList()
|
||||||
|
val packageFqName = facadeFqName.parent()
|
||||||
|
return getDeclarationProvidersByPackage(packageFqName) { file ->
|
||||||
|
facadeFqName.shortName().asString() == PackagePartClassUtils.getFilePartShortName(file.getFileName())
|
||||||
|
}
|
||||||
|
.mapTo(mutableListOf()) { it.kotlinFile }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findInternalFilesForFacade(facadeFqName: FqName): Collection<KtFile> {
|
||||||
|
// no decompiled files here (see the `org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider.findInternalFilesForFacade` KDoc)
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun getDeclarationProvidersByPackage(
|
||||||
|
packageFqName: FqName,
|
||||||
|
crossinline filter: (KtResolveExtensionFile) -> Boolean
|
||||||
|
): Sequence<FileBasedKotlinDeclarationProvider> {
|
||||||
|
return extensionProvider.getFilesByPackage(packageFqName)
|
||||||
|
.filter { filter(it) }
|
||||||
|
.map { createDeclarationProviderByFile(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDeclarationProviderByFile(file: KtResolveExtensionFile): FileBasedKotlinDeclarationProvider {
|
||||||
|
return extensionFileToDeclarationProvider.getOrPut(file) {
|
||||||
|
val factory = KtPsiFactory(
|
||||||
|
ktModule.project,
|
||||||
|
markGenerated = true,
|
||||||
|
eventSystemEnabled = true // so every generated KtFile backed by some VirtualFile
|
||||||
|
)
|
||||||
|
val text = file.buildFileText()
|
||||||
|
val ktFile = createKtFile(factory, file.getFileName(), text)
|
||||||
|
FileBasedKotlinDeclarationProvider(ktFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(KtModuleStructureInternals::class)
|
||||||
|
private fun createKtFile(factory: KtPsiFactory, fileName: String, fileText: String): KtFile {
|
||||||
|
val ktFile = factory.createFile(fileName, fileText)
|
||||||
|
ktFile.virtualFile.analysisExtensionFileContextModule = ktModule
|
||||||
|
return ktFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LLFirResolveExtensionsFileProvider(
|
||||||
|
val extensions: List<KtResolveExtension>,
|
||||||
|
) {
|
||||||
|
fun getFilesByPackage(packageFqName: FqName): Sequence<KtResolveExtensionFile> {
|
||||||
|
return extensions
|
||||||
|
.asSequence()
|
||||||
|
.filter { packageFqName in it.getContainedPackages() }
|
||||||
|
.flatMap { it.getKtFiles() }
|
||||||
|
.filter { it.getFilePackageName() == packageFqName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LLFirResolveExtensionToolPackageProvider(
|
||||||
|
private val packageFilter: LLFirResolveExtensionToolPackageFilter,
|
||||||
|
) : KotlinPackageProvider() {
|
||||||
|
|
||||||
|
private val packageSubPackages: Map<FqName, Set<Name>> by lazy {
|
||||||
|
createSubPackagesMapping(packageFilter.allPackages)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doesPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean =
|
||||||
|
doesKotlinOnlyPackageExist(packageFqName)
|
||||||
|
|
||||||
|
override fun getSubPackageFqNames(packageFqName: FqName, platform: TargetPlatform, nameFilter: (Name) -> Boolean): Set<Name> =
|
||||||
|
getKotlinOnlySubPackagesFqNames(packageFqName, nameFilter)
|
||||||
|
|
||||||
|
override fun doesPlatformSpecificPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean = false
|
||||||
|
|
||||||
|
override fun getPlatformSpecificSubPackagesFqNames(packageFqName: FqName, platform: TargetPlatform, nameFilter: (Name) -> Boolean) =
|
||||||
|
emptySet<Name>()
|
||||||
|
|
||||||
|
override fun doesKotlinOnlyPackageExist(packageFqName: FqName): Boolean =
|
||||||
|
packageFilter.packageExists(packageFqName)
|
||||||
|
|
||||||
|
override fun getKotlinOnlySubPackagesFqNames(packageFqName: FqName, nameFilter: (Name) -> Boolean): Set<Name> {
|
||||||
|
val subPackageNames = packageSubPackages[packageFqName] ?: return emptySet()
|
||||||
|
if (subPackageNames.isEmpty()) return emptySet()
|
||||||
|
return subPackageNames.filterTo(mutableSetOf()) { nameFilter(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createSubPackagesMapping(packages: Set<FqName>): Map<FqName, Set<Name>> {
|
||||||
|
return buildMap<FqName, MutableSet<Name>> {
|
||||||
|
for (packageName in packages) {
|
||||||
|
collectAllSubPackages(packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableMap<FqName, MutableSet<Name>>.collectAllSubPackages(packageName: FqName) {
|
||||||
|
var currentPackage = FqName.ROOT
|
||||||
|
for (packagePart in packageName.pathSegments()) {
|
||||||
|
getOrPut(currentPackage) { mutableSetOf<Name>() }.add(packagePart)
|
||||||
|
currentPackage = currentPackage.child(packagePart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ClassId.getTopLevelShortClassName(): Name {
|
||||||
|
return Name.guessByFirstCharacter(relativeClassName.asString().substringBefore("."))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtResolveExtensionFile.mayHaveTopLevelClassifier(name: Name): Boolean {
|
||||||
|
return name in getTopLevelClassifierNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtResolveExtensionFile.mayHaveTopLevelCallable(name: Name): Boolean {
|
||||||
|
return name in getTopLevelCallableNames()
|
||||||
|
}
|
||||||
+9
-6
@@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.util.ModificationTracker
|
import com.intellij.openapi.util.ModificationTracker
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.SmartPointerManager
|
import com.intellij.psi.SmartPointerManager
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.llResolveExtensionTool
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.*
|
import org.jetbrains.kotlin.analysis.project.structure.*
|
||||||
import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory
|
import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory
|
||||||
import org.jetbrains.kotlin.analysis.providers.KtModuleStateTracker
|
import org.jetbrains.kotlin.analysis.providers.KtModuleStateTracker
|
||||||
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
|
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
@OptIn(PrivateSessionConstructor::class)
|
@OptIn(PrivateSessionConstructor::class)
|
||||||
@@ -51,12 +53,13 @@ abstract class LLFirSession(
|
|||||||
}
|
}
|
||||||
|
|
||||||
modificationTracker = CompositeModificationTracker.createFlattened(
|
modificationTracker = CompositeModificationTracker.createFlattened(
|
||||||
listOfNotNull(
|
buildList {
|
||||||
ExplicitInvalidationTracker(ktModule, isExplicitlyInvalidated),
|
add(ExplicitInvalidationTracker(ktModule, isExplicitlyInvalidated))
|
||||||
ModuleStateModificationTracker(ktModule, validityTracker),
|
add(ModuleStateModificationTracker(ktModule, validityTracker))
|
||||||
outOfBlockTracker,
|
addIfNotNull(outOfBlockTracker)
|
||||||
dependencyTracker
|
add(dependencyTracker)
|
||||||
)
|
llResolveExtensionTool?.modificationTrackers?.let(::addAll)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
initialModificationCount = modificationTracker.modificationCount
|
initialModificationCount = modificationTracker.modificationCount
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.project.structure
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the [org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider] implementations
|
||||||
|
* to store the references on the [KtModule] for which the [VirtualFile] was generated.
|
||||||
|
*/
|
||||||
|
@KtModuleStructureInternals
|
||||||
|
public var VirtualFile.analysisExtensionFileContextModule: KtModule? by UserDataProperty(Key.create("ANALYSIS_CONTEXT_MODULE"))
|
||||||
|
|
||||||
|
@RequiresOptIn("Internal KtModule structure API component which should not be used outside the Analysis API implementation modules as it does not have any compatibility guarantees")
|
||||||
|
public annotation class KtModuleStructureInternals
|
||||||
Reference in New Issue
Block a user