[Analysis API] Add source shadowing for resolve extensions.

KtResolveExtensions are designed to handle IDE analysis use cases where
source might not be available at analysis time, because that source is
generated by an external source generator, such as an annotation
processor or resource compiler. The sources generated by those external
generators can appear in the analysis scope, and cause issues with
source clash - resolution may find the virtual source from the
KtResolveExtension, the on-disk generated source from the external
generator, or both. This can cause issues, because that on-disk
generated source may be stale, and may not have symbols that will exist
the next time the generator is run (or, conversely, may have symbols
that will disappear on the next build).

To solve this, add a `getShadowedScope(): GlobalSearchScope` to
`KtResolveExtension`. Any files in the module that are included in that
scope will be hidden from resolution, allowing the resolve extension to
cleanly replace those files.

^KT-58834 fixed
This commit is contained in:
Justin Paupore
2023-05-22 17:59:47 -07:00
committed by Ilya Kirillov
parent 7c87eb098d
commit f590e88bdd
30 changed files with 357 additions and 82 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.api.descriptors package org.jetbrains.kotlin.analysis.api.descriptors
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.* import org.jetbrains.kotlin.analysis.api.components.*
@@ -61,7 +62,8 @@ class KtFe10AnalysisSession(
override val importOptimizerImpl: KtImportOptimizer = KtFe10ImportOptimizer(this) override val importOptimizerImpl: KtImportOptimizer = KtFe10ImportOptimizer(this)
override val jvmTypeMapperImpl: KtJvmTypeMapper = KtFe10JvmTypeMapper(this) override val jvmTypeMapperImpl: KtJvmTypeMapper = KtFe10JvmTypeMapper(this)
override val symbolInfoProviderImpl: KtSymbolInfoProvider = KtFe10SymbolInfoProvider(this) override val symbolInfoProviderImpl: KtSymbolInfoProvider = KtFe10SymbolInfoProvider(this)
override val analysisScopeProviderImpl: KtAnalysisScopeProvider = KtAnalysisScopeProviderImpl(this, token) override val analysisScopeProviderImpl: KtAnalysisScopeProvider =
KtAnalysisScopeProviderImpl(this, token, shadowedScope = GlobalSearchScope.EMPTY_SCOPE)
override val referenceResolveProviderImpl: KtReferenceResolveProvider = KtFe10ReferenceResolveProvider(this) override val referenceResolveProviderImpl: KtReferenceResolveProvider = KtFe10ReferenceResolveProvider(this)
override val signatureSubstitutorImpl: KtSignatureSubstitutor = KtFe10SignatureSubstitutor(this) override val signatureSubstitutorImpl: KtSignatureSubstitutor = KtFe10SignatureSubstitutor(this)
override val scopeSubstitutionImpl: KtScopeSubstitution = KtFe10ScopeSubstitution(this) override val scopeSubstitutionImpl: KtScopeSubstitution = KtFe10ScopeSubstitution(this)
@@ -114,7 +114,7 @@ private constructor(
override val typesCreatorImpl: KtTypeCreator = KtFirTypeCreator(this, token) override val typesCreatorImpl: KtTypeCreator = KtFirTypeCreator(this, token)
override val analysisScopeProviderImpl: KtAnalysisScopeProvider = KtAnalysisScopeProviderImpl(this, token) override val analysisScopeProviderImpl: KtAnalysisScopeProvider
override val referenceResolveProviderImpl: KtReferenceResolveProvider = KtFirReferenceResolveProvider(this) override val referenceResolveProviderImpl: KtReferenceResolveProvider = KtFirReferenceResolveProvider(this)
@@ -153,9 +153,10 @@ private constructor(
internal val firSymbolProvider: FirSymbolProvider get() = useSiteSession.symbolProvider internal val firSymbolProvider: FirSymbolProvider get() = useSiteSession.symbolProvider
internal val targetPlatform: TargetPlatform get() = useSiteSession.moduleData.platform internal val targetPlatform: TargetPlatform get() = useSiteSession.moduleData.platform
val useSiteAnalysisScope: GlobalSearchScope = analysisScopeProviderImpl.getAnalysisScope()
val extensionTools: List<LLFirResolveExtensionTool> val extensionTools: List<LLFirResolveExtensionTool>
val useSiteAnalysisScope: GlobalSearchScope
val useSiteScopeDeclarationProvider: KotlinDeclarationProvider val useSiteScopeDeclarationProvider: KotlinDeclarationProvider
val useSitePackageProvider: KotlinPackageProvider val useSitePackageProvider: KotlinPackageProvider
@@ -167,6 +168,20 @@ private constructor(
firResolveSession.getSessionFor(dependency).llResolveExtensionTool firResolveSession.getSessionFor(dependency).llResolveExtensionTool
} }
} }
val shadowedScope = GlobalSearchScope.union(
buildSet {
// Add an empty scope to the shadowed set to give GlobalSearchScope.union something
// to work with if there are no extension tools.
// If there are extension tools, any empty scopes, whether from shadowedSearchScope
// on the extension tools or from this add() call, will be ignored.
add(GlobalSearchScope.EMPTY_SCOPE)
extensionTools.mapTo(this) { it.shadowedSearchScope }
}
)
analysisScopeProviderImpl = KtAnalysisScopeProviderImpl(this, token, shadowedScope)
useSiteAnalysisScope = analysisScopeProviderImpl.getAnalysisScope()
useSiteScopeDeclarationProvider = CompositeKotlinDeclarationProvider.create( useSiteScopeDeclarationProvider = CompositeKotlinDeclarationProvider.create(
buildList { buildList {
add(project.createDeclarationProvider(useSiteAnalysisScope, useSiteModule)) add(project.createDeclarationProvider(useSiteAnalysisScope, useSiteModule))
@@ -67,6 +67,24 @@ public class FirIdeNormalAnalysisSourceModuleMultiModuleReferenceResolveWithReso
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/extensionFunction.kt"); runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/extensionFunction.kt");
} }
@Test
@TestMetadata("shadowedDeclaration.kt")
public void testShadowedDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedDeclaration.kt");
}
@Test
@TestMetadata("shadowedJava.kt")
public void testShadowedJava() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedJava.kt");
}
@Test
@TestMetadata("shadowedOverload.kt")
public void testShadowedOverload() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.kt");
}
@Test @Test
@TestMetadata("topLevelFunction.kt") @TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception { public void testTopLevelFunction() throws Exception {
@@ -58,6 +58,24 @@ public class FirIdeNormalAnalysisSourceModuleSingleModuleReferenceResolveWithRes
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/extensionFunction.kt"); runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/extensionFunction.kt");
} }
@Test
@TestMetadata("shadowedDeclaration.kt")
public void testShadowedDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedDeclaration.kt");
}
@Test
@TestMetadata("shadowedJava.kt")
public void testShadowedJava() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedJava.kt");
}
@Test
@TestMetadata("shadowedOverload.kt")
public void testShadowedOverload() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.kt");
}
@Test @Test
@TestMetadata("topLevelFunction.kt") @TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception { public void testTopLevelFunction() throws Exception {
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.psi.psiUtil.contains
class KtAnalysisScopeProviderImpl( class KtAnalysisScopeProviderImpl(
override val analysisSession: KtAnalysisSession, override val analysisSession: KtAnalysisSession,
override val token: KtLifetimeToken override val token: KtLifetimeToken,
private val shadowedScope: GlobalSearchScope
) : KtAnalysisScopeProvider() { ) : KtAnalysisScopeProvider() {
private val baseResolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) { private val baseResolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
@@ -31,13 +32,13 @@ class KtAnalysisScopeProviderImpl(
} }
private val resolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) { private val resolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
KtAnalysisScopeProviderResolveScope(baseResolveScope, analysisSession.useSiteModule) KtAnalysisScopeProviderResolveScope(baseResolveScope, analysisSession.useSiteModule, shadowedScope)
} }
override fun getAnalysisScope(): GlobalSearchScope = resolveScope override fun getAnalysisScope(): GlobalSearchScope = resolveScope
override fun canBeAnalysed(psi: PsiElement): Boolean { override fun canBeAnalysed(psi: PsiElement): Boolean {
return baseResolveScope.contains(psi) return (baseResolveScope.contains(psi) && !shadowedScope.contains(psi))
|| psi.isFromGeneratedModule() || psi.isFromGeneratedModule()
} }
@@ -49,12 +50,17 @@ class KtAnalysisScopeProviderImpl(
private class KtAnalysisScopeProviderResolveScope( private class KtAnalysisScopeProviderResolveScope(
private val base: GlobalSearchScope, private val base: GlobalSearchScope,
private val useSiteModule: KtModule private val useSiteModule: KtModule,
private val shadowed: GlobalSearchScope,
) : GlobalSearchScope() { ) : GlobalSearchScope() {
override fun getProject(): Project? = base.project override fun getProject(): Project? = base.project
override fun isSearchInModuleContent(aModule: Module): Boolean = base.isSearchInModuleContent(aModule) override fun isSearchInModuleContent(aModule: Module): Boolean = base.isSearchInModuleContent(aModule)
override fun isSearchInLibraries(): Boolean = base.isSearchInLibraries override fun isSearchInLibraries(): Boolean = base.isSearchInLibraries
override fun contains(file: VirtualFile): Boolean = base.contains(file) || file.isFromGeneratedModule(useSiteModule) override fun contains(file: VirtualFile): Boolean =
(base.contains(file) && !shadowed.contains(file)) || file.isFromGeneratedModule(useSiteModule)
override fun toString() =
"Analysis scope for $useSiteModule (base: $base, shadowed: $shadowed)"
} }
@OptIn(KtModuleStructureInternals::class) @OptIn(KtModuleStructureInternals::class)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtMultiModuleResolveExtensionProviderForTest import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtMultiModuleResolveExtensionProviderForTest
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
@@ -12,6 +13,12 @@ import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
abstract class AbstractMultiModuleReferenceResolveWithResolveExtensionTest : AbstractReferenceResolveWithResolveExtensionTest() { abstract class AbstractMultiModuleReferenceResolveWithResolveExtensionTest : AbstractReferenceResolveWithResolveExtensionTest() {
override fun createResolveExtensionProvider(files: List<KtResolveExtensionFile>, packages: Set<FqName>): KtResolveExtensionProvider = override fun createResolveExtensionProvider(
KtMultiModuleResolveExtensionProviderForTest(files, packages) { it is KtSourceModule && it.moduleName == "extendedModule" } files: List<KtResolveExtensionFile>,
packages: Set<FqName>,
shadowedScope: GlobalSearchScope,
): KtResolveExtensionProvider =
KtMultiModuleResolveExtensionProviderForTest(files, packages, shadowedScope) { module ->
module is KtSourceModule && module.moduleName == "extendedModule"
}
} }
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references
import com.intellij.openapi.module.Module
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtResolveExtensionFileForTests import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtResolveExtensionFileForTests
import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtResolveExtensionProviderForTestPreAnalysisHandler import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtResolveExtensionProviderForTestPreAnalysisHandler
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile
@@ -17,17 +20,22 @@ abstract class AbstractReferenceResolveWithResolveExtensionTest : AbstractRefere
abstract fun createResolveExtensionProvider( abstract fun createResolveExtensionProvider(
files: List<KtResolveExtensionFile>, files: List<KtResolveExtensionFile>,
packages: Set<FqName>, packages: Set<FqName>,
shadowedScope: GlobalSearchScope,
): KtResolveExtensionProvider ): KtResolveExtensionProvider
override fun configureTest(builder: TestConfigurationBuilder) { override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder) super.configureTest(builder)
val provider = createResolveExtensionProvider( val provider = createResolveExtensionProvider(
listOf( files = listOf(
KtResolveExtensionFileForTests( KtResolveExtensionFileForTests(
"extension1.kt", "extension1.kt",
packageName = FqName("generated"), packageName = FqName("generated"),
topLevelClassifiersNames = setOf("GeneratedClass1"), topLevelClassifiersNames = setOf("GeneratedClass1"),
topLevelCallableNames = setOf("generatedTopLevelFunction1", "generatedTopLevelExtensionFunction1"), topLevelCallableNames = setOf(
"generatedTopLevelFunction1",
"generatedTopLevelExtensionFunction1",
"generatedOverloadedExtensionFunction",
),
fileText = """|package generated fileText = """|package generated
| |
|class GeneratedClass1 { |class GeneratedClass1 {
@@ -37,6 +45,8 @@ abstract class AbstractReferenceResolveWithResolveExtensionTest : AbstractRefere
|fun generatedTopLevelFunction1(): GeneratedClass2 |fun generatedTopLevelFunction1(): GeneratedClass2
| |
|fun String.generatedTopLevelExtensionFunction1(boolean: Boolean): Int |fun String.generatedTopLevelExtensionFunction1(boolean: Boolean): Int
|
|fun Any.generatedOverloadedExtensionFunction(): Int
""".trimMargin() """.trimMargin()
), ),
KtResolveExtensionFileForTests( KtResolveExtensionFileForTests(
@@ -52,7 +62,14 @@ abstract class AbstractReferenceResolveWithResolveExtensionTest : AbstractRefere
""".trimMargin(), """.trimMargin(),
) )
), ),
setOf(FqName("generated")) packages = setOf(FqName("generated")),
shadowedScope = object : GlobalSearchScope() {
override fun contains(file: VirtualFile): Boolean = ".hidden." in file.name
override fun isSearchInModuleContent(aModule: Module): Boolean = false
override fun isSearchInLibraries(): Boolean = false
}
) )
with(builder) { with(builder) {
usePreAnalysisHandlers(::KtResolveExtensionProviderForTestPreAnalysisHandler.bind(listOf(provider))) usePreAnalysisHandlers(::KtResolveExtensionProviderForTestPreAnalysisHandler.bind(listOf(provider)))
@@ -5,12 +5,17 @@
package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtSingleModuleResolveExtensionProviderForTest import org.jetbrains.kotlin.analysis.api.impl.base.test.util.KtSingleModuleResolveExtensionProviderForTest
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
abstract class AbstractSingleModuleReferenceResolveWithResolveExtensionTest : AbstractReferenceResolveWithResolveExtensionTest() { abstract class AbstractSingleModuleReferenceResolveWithResolveExtensionTest : AbstractReferenceResolveWithResolveExtensionTest() {
override fun createResolveExtensionProvider(files: List<KtResolveExtensionFile>, packages: Set<FqName>): KtResolveExtensionProvider = override fun createResolveExtensionProvider(
KtSingleModuleResolveExtensionProviderForTest(files, packages) files: List<KtResolveExtensionFile>,
packages: Set<FqName>,
shadowedScope: GlobalSearchScope,
): KtResolveExtensionProvider =
KtSingleModuleResolveExtensionProviderForTest(files, packages, shadowedScope)
} }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.util
import com.intellij.mock.MockProject import com.intellij.mock.MockProject
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
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.resolve.extensions.KtResolveExtension 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.KtResolveExtensionFile
@@ -25,20 +26,22 @@ import org.jetbrains.kotlin.test.services.TestServices
class KtSingleModuleResolveExtensionProviderForTest( class KtSingleModuleResolveExtensionProviderForTest(
private val files: List<KtResolveExtensionFile>, private val files: List<KtResolveExtensionFile>,
private val packages: Set<FqName>, private val packages: Set<FqName>,
private val shadowedScope: GlobalSearchScope,
) : KtResolveExtensionProvider() { ) : KtResolveExtensionProvider() {
override fun provideExtensionsFor(module: KtModule): List<KtResolveExtension> { override fun provideExtensionsFor(module: KtModule): List<KtResolveExtension> {
return listOf(KtResolveExtensionForTest(files, packages)) return listOf(KtResolveExtensionForTest(files, packages, shadowedScope))
} }
} }
class KtMultiModuleResolveExtensionProviderForTest( class KtMultiModuleResolveExtensionProviderForTest(
private val files: List<KtResolveExtensionFile>, private val files: List<KtResolveExtensionFile>,
private val packages: Set<FqName>, private val packages: Set<FqName>,
private val shadowedScope: GlobalSearchScope,
private val hasResolveExtension: (KtModule) -> Boolean, private val hasResolveExtension: (KtModule) -> Boolean,
) : KtResolveExtensionProvider() { ) : KtResolveExtensionProvider() {
override fun provideExtensionsFor(module: KtModule): List<KtResolveExtension> { override fun provideExtensionsFor(module: KtModule): List<KtResolveExtension> {
if (!hasResolveExtension(module)) return emptyList() if (!hasResolveExtension(module)) return emptyList()
return listOf(KtResolveExtensionForTest(files, packages)) return listOf(KtResolveExtensionForTest(files, packages, shadowedScope))
} }
} }
@@ -59,10 +62,12 @@ class KtResolveExtensionProviderForTestPreAnalysisHandler(
class KtResolveExtensionForTest( class KtResolveExtensionForTest(
private val files: List<KtResolveExtensionFile>, private val files: List<KtResolveExtensionFile>,
private val packages: Set<FqName>, private val packages: Set<FqName>,
private val shadowedScope: GlobalSearchScope,
) : KtResolveExtension() { ) : KtResolveExtension() {
override fun getKtFiles(): List<KtResolveExtensionFile> = files override fun getKtFiles(): List<KtResolveExtensionFile> = files
override fun getModificationTracker(): ModificationTracker = ModificationTracker.NEVER_CHANGED override fun getModificationTracker(): ModificationTracker = ModificationTracker.NEVER_CHANGED
override fun getContainedPackages(): Set<FqName> = packages override fun getContainedPackages(): Set<FqName> = packages
override fun getShadowedScope(): GlobalSearchScope = shadowedScope
} }
class KtResolveExtensionFileForTests( class KtResolveExtensionFileForTests(
@@ -67,6 +67,24 @@ public class FirStandaloneNormalAnalysisSourceModuleMultiModuleReferenceResolveW
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/extensionFunction.kt"); runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/extensionFunction.kt");
} }
@Test
@TestMetadata("shadowedDeclaration.kt")
public void testShadowedDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedDeclaration.kt");
}
@Test
@TestMetadata("shadowedJava.kt")
public void testShadowedJava() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedJava.kt");
}
@Test
@TestMetadata("shadowedOverload.kt")
public void testShadowedOverload() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.kt");
}
@Test @Test
@TestMetadata("topLevelFunction.kt") @TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception { public void testTopLevelFunction() throws Exception {
@@ -58,6 +58,24 @@ public class FirStandaloneNormalAnalysisSourceModuleSingleModuleReferenceResolve
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/extensionFunction.kt"); runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/extensionFunction.kt");
} }
@Test
@TestMetadata("shadowedDeclaration.kt")
public void testShadowedDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedDeclaration.kt");
}
@Test
@TestMetadata("shadowedJava.kt")
public void testShadowedJava() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedJava.kt");
}
@Test
@TestMetadata("shadowedOverload.kt")
public void testShadowedOverload() throws Exception {
runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.kt");
}
@Test @Test
@TestMetadata("topLevelFunction.kt") @TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception { public void testTopLevelFunction() throws Exception {
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.api.resolve.extensions package org.jetbrains.kotlin.analysis.api.resolve.extensions
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
/** /**
@@ -53,4 +54,17 @@ public abstract class KtResolveExtension {
* @see KtResolveExtension * @see KtResolveExtension
*/ */
public abstract fun getContainedPackages(): Set<FqName> public abstract fun getContainedPackages(): Set<FqName>
/**
* Returns the scope of files that should be shadowed by the files provided by [getKtFiles].
*
* Any files in the module that are included in this scope will be removed from analysis results. This allows the files provided by
* [getKtFiles] to cleanly replace those files from the module.
*
* If this resolve extension is being used to generate declarations that would normally be provided by sources generated by an external
* build task, such as a resource compiler or annotation processor, the resolve extension should provide a scope here that covers those
* externally generated sources. This will prevent collisions between the definitions provided by [getKtFiles] and those provided by the
* (potentially stale) externally generated sources.
*/
public open fun getShadowedScope(): GlobalSearchScope = GlobalSearchScope.EMPTY_SCOPE
} }
@@ -0,0 +1,15 @@
// UNRESOLVED_REFERENCE
// MODULE: extendedModule
// FILE: declarations.hidden.kt
package foo
fun bar() = "baz"
// MODULE: dependency2
// MODULE: main(extendedModule, dependency2)()()
// FILE: main.kt
fun main() {
val x = foo.<caret>bar()
}
@@ -0,0 +1,19 @@
// UNRESOLVED_REFERENCE
// MODULE: extendedModule
// FILE: TestClass.hidden.java
package foo;
public class TestClass {
public TestClass() {}
}
// MODULE: dependency2
// MODULE: main(extendedModule, dependency2)()()
// FILE: main.kt
package foo
fun main() {
val x = <caret>TestClass()
}
@@ -0,0 +1,15 @@
// MODULE: extendedModule
// FILE: generated.hidden.kt
package generated
fun String.generatedOverloadedExtensionFunction(): Int = TODO()
// MODULE: dependency2
// MODULE: main(extendedModule, dependency2)()()
// FILE: main.kt
import generated.*
fun main() {
"string".generatedOverloadedExtension<caret>Function()
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in generated) fun kotlin.Any.generatedOverloadedExtensionFunction(): kotlin.Int
@@ -0,0 +1,11 @@
// UNRESOLVED_REFERENCE
// FILE: declarations.hidden.kt
package foo
fun bar() = "baz"
// FILE: main.kt
fun main() {
val x = foo.<caret>bar()
}
@@ -0,0 +1,15 @@
// UNRESOLVED_REFERENCE
// FILE: TestClass.hidden.java
package foo;
public class TestClass {
public TestClass() {}
}
// FILE: main.kt
package foo
fun main() {
val x = <caret>TestClass()
}
@@ -0,0 +1,11 @@
// FILE: generated.hidden.kt
package generated
fun String.generatedOverloadedExtensionFunction(): Int = TODO()
// FILE: main.kt
import generated.*
fun main() {
"string".generatedOverloadedExtension<caret>Function()
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in generated) fun kotlin.Any.generatedOverloadedExtensionFunction(): kotlin.Int
@@ -92,15 +92,3 @@ internal fun LLFirSourcesSession.registerCompilerPluginServices(
) )
} }
internal fun createJavaSymbolProvider(
firSession: FirSession,
moduleData: LLFirModuleData,
project: Project,
contentScope: GlobalSearchScope
): JavaSymbolProvider {
return JavaSymbolProvider(
firSession,
FirJavaFacadeForSource(firSession, moduleData, project.createJavaClassFinder(contentScope))
)
}
@@ -90,9 +90,9 @@ internal class LLFirCombinedJavaSymbolProvider private constructor(
override fun getPackage(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) } override fun getPackage(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) }
companion object { companion object {
fun merge(session: FirSession, project: Project, providers: List<JavaSymbolProvider>): FirSymbolProvider? = fun merge(session: FirSession, project: Project, providers: List<LLFirJavaSymbolProvider>): FirSymbolProvider? =
if (providers.size > 1) { if (providers.size > 1) {
val combinedScope = GlobalSearchScope.union(providers.map { it.session.llFirModuleData.ktModule.contentScope }) val combinedScope = GlobalSearchScope.union(providers.map { it.searchScope })
val javaClassFinder = project.createJavaClassFinder(combinedScope) val javaClassFinder = project.createJavaClassFinder(combinedScope)
LLFirCombinedJavaSymbolProvider(session, project, providers, javaClassFinder) LLFirCombinedJavaSymbolProvider(session, project, providers, javaClassFinder)
} else providers.singleOrNull() } else providers.singleOrNull()
@@ -0,0 +1,24 @@
/*
* 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.providers
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.java.FirJavaFacadeForSource
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.load.java.createJavaClassFinder
internal class LLFirJavaSymbolProvider(
firSession: FirSession,
moduleData: LLFirModuleData,
project: Project,
val searchScope: GlobalSearchScope
) : JavaSymbolProvider(
firSession,
FirJavaFacadeForSource(firSession, moduleData, project.createJavaClassFinder(searchScope))
)
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.providers package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.SyntheticFirClassProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.SyntheticFirClassProvider
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.fir.FirSession
import org.jetbrains.kotlin.fir.NoMutableState import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.ThreadSafeMutableState import org.jetbrains.kotlin.fir.ThreadSafeMutableState
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
@@ -29,22 +29,23 @@ import org.jetbrains.kotlin.psi.KtProperty
@ThreadSafeMutableState @ThreadSafeMutableState
internal class LLFirProvider( internal class LLFirProvider(
val session: FirSession, val session: LLFirSession,
private val moduleComponents: LLFirModuleResolveComponents, private val moduleComponents: LLFirModuleResolveComponents,
private val declarationProvider: KotlinDeclarationProvider,
packageProvider: KotlinPackageProvider,
canContainKotlinPackage: Boolean, canContainKotlinPackage: Boolean,
declarationProviderFactory: (GlobalSearchScope) -> KotlinDeclarationProvider?,
) : FirProvider() { ) : FirProvider() {
override val symbolProvider: FirSymbolProvider = SymbolProvider() override val symbolProvider: FirSymbolProvider = SymbolProvider()
private val providerHelper = LLFirProviderHelper( private val providerHelper = LLFirProviderHelper(
session, session,
moduleComponents.firFileBuilder, moduleComponents.firFileBuilder,
declarationProvider,
packageProvider,
canContainKotlinPackage, canContainKotlinPackage,
declarationProviderFactory,
) )
val searchScope: GlobalSearchScope
get() = providerHelper.searchScope
override val isPhasedFirAllowed: Boolean get() = true override val isPhasedFirAllowed: Boolean get() = true
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? = override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? =
@@ -103,9 +104,7 @@ internal class LLFirProvider(
override fun getFirFilesByPackage(fqName: FqName): List<FirFile> = error("Should not be called in FIR IDE") override fun getFirFilesByPackage(fqName: FqName): List<FirFile> = error("Should not be called in FIR IDE")
override fun getClassNamesInPackage(fqName: FqName): Set<Name> = providerHelper.getTopLevelClassNamesInPackage(fqName)
override fun getClassNamesInPackage(fqName: FqName): Set<Name> =
declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(fqName)
@NoMutableState @NoMutableState
internal inner class SymbolProvider : LLFirKotlinSymbolProvider(session) { internal inner class SymbolProvider : LLFirKotlinSymbolProvider(session) {
@@ -5,18 +5,19 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.providers package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
import com.intellij.psi.search.GlobalSearchScope
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.CompositeKotlinPackageProvider 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.LLFirResolveExtensionTool
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.llResolveExtensionTool import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.llResolveExtensionTool
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
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.LLFirKotlinSymbolNamesProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolNamesProvider
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.createPackageProvider
import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.CompositeKotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.CompositeKotlinDeclarationProvider
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
@@ -35,27 +36,37 @@ import org.jetbrains.kotlin.psi.KtClassLikeDeclaration
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
internal class LLFirProviderHelper( internal class LLFirProviderHelper(
firSession: FirSession, firSession: LLFirSession,
private val firFileBuilder: LLFirFileBuilder, private val firFileBuilder: LLFirFileBuilder,
mainDeclarationProvider: KotlinDeclarationProvider,
mainPackageProvider: KotlinPackageProvider,
canContainKotlinPackage: Boolean, canContainKotlinPackage: Boolean,
declarationProviderFactory: (GlobalSearchScope) -> KotlinDeclarationProvider?
) { ) {
private val extensionTool: LLFirResolveExtensionTool? = firSession.llResolveExtensionTool private val extensionTool: LLFirResolveExtensionTool? = firSession.llResolveExtensionTool
val searchScope: GlobalSearchScope =
firSession.ktModule.contentScope.run {
val notShadowedScope = extensionTool?.shadowedSearchScope?.let { GlobalSearchScope.notScope(it) }
if (notShadowedScope != null) {
this.intersectWith(notShadowedScope)
} else {
this
}
}
val declarationProvider = CompositeKotlinDeclarationProvider.create( val declarationProvider = CompositeKotlinDeclarationProvider.create(
listOfNotNull( listOfNotNull(
mainDeclarationProvider, declarationProviderFactory(searchScope),
extensionTool?.declarationProvider, extensionTool?.declarationProvider,
) )
) )
private val packageProvider = CompositeKotlinPackageProvider.create( private val packageProvider = CompositeKotlinPackageProvider.create(
listOfNotNull( listOfNotNull(
mainPackageProvider, firSession.project.createPackageProvider(searchScope),
extensionTool?.packageProvider, extensionTool?.packageProvider,
) )
) )
private val allowKotlinPackage = canContainKotlinPackage || private val allowKotlinPackage = canContainKotlinPackage ||
firSession.languageVersionSettings.getFlag(AnalysisFlags.allowKotlinPackage) firSession.languageVersionSettings.getFlag(AnalysisFlags.allowKotlinPackage)
@@ -100,6 +111,11 @@ internal class LLFirProviderHelper(
return classifierByClassId.getValue(classId, classLikeDeclaration) return classifierByClassId.getValue(classId, classLikeDeclaration)
} }
fun getTopLevelClassNamesInPackage(packageFqName: FqName): Set<Name> {
if (!allowKotlinPackage && packageFqName.isKotlinPackage()) return emptySet()
return declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName)
}
fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> { fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> {
if (!allowKotlinPackage && packageFqName.isKotlinPackage()) return emptyList() if (!allowKotlinPackage && packageFqName.isKotlinPackage()) return emptyList()
val callableId = CallableId(packageFqName, name) val callableId = CallableId(packageFqName, name)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.KtAnalysisAllowanceManager import org.jetbrains.kotlin.analysis.api.KtAnalysisAllowanceManager
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtension 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.KtResolveExtensionFile
@@ -40,6 +41,7 @@ abstract class LLFirResolveExtensionTool : FirSessionComponent {
abstract val declarationProvider: LLFirResolveExtensionToolDeclarationProvider abstract val declarationProvider: LLFirResolveExtensionToolDeclarationProvider
abstract val packageProvider: KotlinPackageProvider abstract val packageProvider: KotlinPackageProvider
abstract val packageFilter: LLFirResolveExtensionToolPackageFilter abstract val packageFilter: LLFirResolveExtensionToolPackageFilter
abstract val shadowedSearchScope: GlobalSearchScope
internal abstract val symbolNamesProvider: FirSymbolNamesProvider internal abstract val symbolNamesProvider: FirSymbolNamesProvider
} }
@@ -57,13 +59,19 @@ internal class LLFirNonEmptyResolveExtensionTool(
override val packageFilter = LLFirResolveExtensionToolPackageFilter(extensions) override val packageFilter = LLFirResolveExtensionToolPackageFilter(extensions)
override val modificationTrackers by lazy { extensions.map { it.getModificationTracker() } } override val modificationTrackers by lazy { forbidAnalysis { extensions.map { it.getModificationTracker() } } }
override val declarationProvider: LLFirResolveExtensionToolDeclarationProvider = override val declarationProvider: LLFirResolveExtensionToolDeclarationProvider =
LLFirResolveExtensionToolDeclarationProvider(fileProvider, session.ktModule) LLFirResolveExtensionToolDeclarationProvider(fileProvider, session.ktModule)
override val packageProvider: KotlinPackageProvider = LLFirResolveExtensionToolPackageProvider(packageFilter) override val packageProvider: KotlinPackageProvider = LLFirResolveExtensionToolPackageProvider(packageFilter)
override val shadowedSearchScope by lazy {
forbidAnalysis {
GlobalSearchScope.union(extensions.mapTo(mutableSetOf()) { it.getShadowedScope() })
}
}
override val symbolNamesProvider: FirSymbolNamesProvider = LLFirResolveExtensionToolSymbolNamesProvider(packageFilter, fileProvider) override val symbolNamesProvider: FirSymbolNamesProvider = LLFirResolveExtensionToolSymbolNamesProvider(packageFilter, fileProvider)
} }
@@ -310,7 +318,7 @@ internal class LLFirResolveExtensionsFileProvider(
.filter { it.getFilePackageName() == packageFqName } .filter { it.getFilePackageName() == packageFqName }
} }
fun getAllFiles(): Sequence<KtResolveExtensionFile> { fun getAllFiles(): Sequence<KtResolveExtensionFile> = forbidAnalysis {
return extensions return extensions
.asSequence() .asSequence()
.flatMap { it.getKtFiles() } .flatMap { it.getKtFiles() }
@@ -15,11 +15,11 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveCompone
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.* import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.* import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.*
import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.createAnnotationResolver import org.jetbrains.kotlin.analysis.providers.createAnnotationResolver
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.EmptyKotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.FileBasedKotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.FileBasedKotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.impl.util.mergeInto
import org.jetbrains.kotlin.analysis.utils.trackers.CompositeModificationTracker import org.jetbrains.kotlin.analysis.utils.trackers.CompositeModificationTracker
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -48,7 +48,6 @@ import org.jetbrains.kotlin.scripting.compiler.plugin.FirScriptingSamWithReceive
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
import org.jetbrains.kotlin.analysis.providers.impl.util.mergeInto
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
internal abstract class LLFirAbstractSessionFactory(protected val project: Project) { internal abstract class LLFirAbstractSessionFactory(protected val project: Project) {
@@ -66,7 +65,6 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope
val dependencies = collectSourceModuleDependencies(module) val dependencies = collectSourceModuleDependencies(module)
val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies) val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies)
@@ -90,10 +88,10 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
val provider = LLFirProvider( val provider = LLFirProvider(
this, this,
components, components,
FileBasedKotlinDeclarationProvider(module.file),
project.createPackageProvider(contentScope),
canContainKotlinPackage = true, canContainKotlinPackage = true,
) ) { scope ->
scope.createScopedDeclarationProviderForFile(module.file)
}
register(FirProvider::class, provider) register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
@@ -103,7 +101,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
add(builtinsSession.symbolProvider) add(builtinsSession.symbolProvider)
}) })
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope) val javaSymbolProvider = LLFirJavaSymbolProvider(this, moduleData, project, provider.searchScope)
register(JavaSymbolProvider::class, javaSymbolProvider) register(JavaSymbolProvider::class, javaSymbolProvider)
register( register(
@@ -170,10 +168,10 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
val provider = LLFirProvider( val provider = LLFirProvider(
this, this,
components, components,
if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider,
project.createPackageProvider(module.contentScope),
canContainKotlinPackage = true, canContainKotlinPackage = true,
) ) { scope ->
ktFile?.let { scope.createScopedDeclarationProviderForFile(it) }
}
register(FirProvider::class, provider) register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
@@ -226,8 +224,6 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
components.session = session components.session = session
val moduleData = createModuleData(session) val moduleData = createModuleData(session)
val contentScope = module.contentScope
return session.apply { return session.apply {
registerModuleData(moduleData) registerModuleData(moduleData)
@@ -240,16 +236,16 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
val firProvider = LLFirProvider( val firProvider = LLFirProvider(
this, this,
components, components,
project.createDeclarationProvider(contentScope, module),
project.createPackageProvider(contentScope),
/* Source modules can contain `kotlin` package only if `-Xallow-kotlin-package` is specified, this is handled in LLFirProvider */ /* Source modules can contain `kotlin` package only if `-Xallow-kotlin-package` is specified, this is handled in LLFirProvider */
canContainKotlinPackage = false, canContainKotlinPackage = false,
) ) { scope ->
project.createDeclarationProvider(scope, module)
}
register(FirProvider::class, firProvider) register(FirProvider::class, firProvider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
registerCompilerPluginServices(contentScope, project, module) registerCompilerPluginServices(firProvider.searchScope, project, module)
registerCompilerPluginExtensions(project, module) registerCompilerPluginExtensions(project, module)
registerCommonComponentsAfterExtensionsAreConfigured() registerCommonComponentsAfterExtensionsAreConfigured()
@@ -273,7 +269,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
} }
val context = SourceSessionCreationContext( val context = SourceSessionCreationContext(
moduleData, contentScope, firProvider, dependencyProvider, syntheticFunctionInterfaceProvider, moduleData, firProvider.searchScope, firProvider, dependencyProvider, syntheticFunctionInterfaceProvider,
switchableExtensionDeclarationsSymbolProvider, switchableExtensionDeclarationsSymbolProvider,
) )
additionalSessionConfiguration(context) additionalSessionConfiguration(context)
@@ -320,22 +316,20 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
registerCommonComponentsAfterExtensionsAreConfigured() registerCommonComponentsAfterExtensionsAreConfigured()
registerResolveComponents() registerResolveComponents()
val contentScope = module.contentScope
val firProvider = LLFirProvider( val firProvider = LLFirProvider(
this, this,
components, components,
project.createDeclarationProvider(contentScope, module),
project.createPackageProvider(contentScope),
canContainKotlinPackage = true, canContainKotlinPackage = true,
) ) { scope ->
project.createDeclarationProvider(scope, module)
}
register(FirProvider::class, firProvider) register(FirProvider::class, firProvider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
// We need FirRegisteredPluginAnnotations during extensions' registration process // We need FirRegisteredPluginAnnotations during extensions' registration process
val annotationsResolver = project.createAnnotationResolver(contentScope) val annotationsResolver = project.createAnnotationResolver(firProvider.searchScope)
register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver)) register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver))
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider) register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
@@ -360,7 +354,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider) register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this)) register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
val context = LibrarySessionCreationContext(moduleData, contentScope, firProvider, dependencyProvider) val context = LibrarySessionCreationContext(moduleData, firProvider.searchScope, firProvider, dependencyProvider)
additionalSessionConfiguration(context) additionalSessionConfiguration(context)
LLFirSessionConfigurator.configure(this) LLFirSessionConfigurator.configure(this)
@@ -504,8 +498,21 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
) { ) {
mergeInto(destination) { mergeInto(destination) {
merge<LLFirProvider.SymbolProvider> { LLFirCombinedKotlinSymbolProvider.merge(session, project, it) } merge<LLFirProvider.SymbolProvider> { LLFirCombinedKotlinSymbolProvider.merge(session, project, it) }
merge<JavaSymbolProvider> { LLFirCombinedJavaSymbolProvider.merge(session, project, it) } merge<LLFirJavaSymbolProvider> { LLFirCombinedJavaSymbolProvider.merge(session, project, it) }
merge<FirExtensionSyntheticFunctionInterfaceProvider> { LLFirCombinedSyntheticFunctionSymbolProvider.merge(session, it) } merge<FirExtensionSyntheticFunctionInterfaceProvider> { LLFirCombinedSyntheticFunctionSymbolProvider.merge(session, it) }
} }
} }
/**
* Creates a single-file [KotlinDeclarationProvider] for the provided file, if it is in the search scope.
*
* Otherwise, returns `null`.
*/
private fun GlobalSearchScope.createScopedDeclarationProviderForFile(file: KtFile): KotlinDeclarationProvider? =
// KtFiles without a backing VirtualFile can't be covered by a shadow scope, and are thus assumed in-scope.
if (file.virtualFile == null || contains(file.virtualFile)) {
FileBasedKotlinDeclarationProvider(file)
} else {
null
}
} }
@@ -25,7 +25,7 @@ internal class LLFirJvmSessionFactory(project: Project) : LLFirAbstractSessionFa
return doCreateSourcesSession(module, FirKotlinScopeProvider(::wrapScopeWithJvmMapped)) { context -> return doCreateSourcesSession(module, FirKotlinScopeProvider(::wrapScopeWithJvmMapped)) { context ->
registerCommonJavaComponents(JavaModuleResolver.getInstance(project)) registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerJavaSpecificResolveComponents() registerJavaSpecificResolveComponents()
val javaSymbolProvider = createJavaSymbolProvider(this, context.moduleData, project, context.contentScope) val javaSymbolProvider = LLFirJavaSymbolProvider(this, context.moduleData, project, context.contentScope)
register(JavaSymbolProvider::class, javaSymbolProvider) register(JavaSymbolProvider::class, javaSymbolProvider)
register( register(
@@ -50,7 +50,7 @@ internal class LLFirJvmSessionFactory(project: Project) : LLFirAbstractSessionFa
return doCreateLibrarySession(module) { context -> return doCreateLibrarySession(module) { context ->
registerCommonJavaComponents(JavaModuleResolver.getInstance(project)) registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerJavaSpecificResolveComponents() registerJavaSpecificResolveComponents()
val javaSymbolProvider = createJavaSymbolProvider(this, context.moduleData, project, context.contentScope) val javaSymbolProvider = LLFirJavaSymbolProvider(this, context.moduleData, project, context.contentScope)
register( register(
FirSymbolProvider::class, FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider( LLFirModuleWithDependenciesSymbolProvider(
@@ -13,7 +13,7 @@ import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirInternals import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirInternals
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.JvmFirDeserializedSymbolProviderFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.JvmFirDeserializedSymbolProviderFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.createJavaSymbolProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirJavaSymbolProvider
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
@@ -56,7 +56,7 @@ class JvmStubBasedDeserializedSymbolProviderFactory : JvmFirDeserializedSymbolPr
FirDeclarationOrigin.Library FirDeclarationOrigin.Library
) )
) )
add(createJavaSymbolProvider(session, moduleData, project, scope)) add(LLFirJavaSymbolProvider(session, moduleData, project, scope))
} }
} }
} }
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.name.Name
// For library and incremental compilation sessions use `KotlinDeserializedJvmSymbolsProvider` // For library and incremental compilation sessions use `KotlinDeserializedJvmSymbolsProvider`
// in order to load Kotlin classes as well. // in order to load Kotlin classes as well.
//Also used in IDE for loading java classes separately from stub based kotlin classes //Also used in IDE for loading java classes separately from stub based kotlin classes
class JavaSymbolProvider( open class JavaSymbolProvider(
session: FirSession, session: FirSession,
private val javaFacade: FirJavaFacade, private val javaFacade: FirJavaFacade,
) : FirSymbolProvider(session) { ) : FirSymbolProvider(session) {