[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
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/KtFe10AnalysisSession.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/KtFe10AnalysisSession.kt index 1054002..902a0b4 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/KtFe10AnalysisSession.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/KtFe10AnalysisSession.kt
@@ -6,6 +6,7 @@ package org.jetbrains.kotlin.analysis.api.descriptors 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.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.components.* @@ -61,7 +62,8 @@ override val importOptimizerImpl: KtImportOptimizer = KtFe10ImportOptimizer(this) override val jvmTypeMapperImpl: KtJvmTypeMapper = KtFe10JvmTypeMapper(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 signatureSubstitutorImpl: KtSignatureSubstitutor = KtFe10SignatureSubstitutor(this) override val scopeSubstitutionImpl: KtScopeSubstitution = KtFe10ScopeSubstitution(this)
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSession.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSession.kt index 4704c7b..9dcf00c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSession.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSession.kt
@@ -114,7 +114,7 @@ override val typesCreatorImpl: KtTypeCreator = KtFirTypeCreator(this, token) - override val analysisScopeProviderImpl: KtAnalysisScopeProvider = KtAnalysisScopeProviderImpl(this, token) + override val analysisScopeProviderImpl: KtAnalysisScopeProvider override val referenceResolveProviderImpl: KtReferenceResolveProvider = KtFirReferenceResolveProvider(this) @@ -153,9 +153,10 @@ internal val firSymbolProvider: FirSymbolProvider get() = useSiteSession.symbolProvider internal val targetPlatform: TargetPlatform get() = useSiteSession.moduleData.platform - val useSiteAnalysisScope: GlobalSearchScope = analysisScopeProviderImpl.getAnalysisScope() - val extensionTools: List<LLFirResolveExtensionTool> + + val useSiteAnalysisScope: GlobalSearchScope + val useSiteScopeDeclarationProvider: KotlinDeclarationProvider val useSitePackageProvider: KotlinPackageProvider @@ -167,6 +168,20 @@ 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( buildList { add(project.createDeclarationProvider(useSiteAnalysisScope, useSiteModule))
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java index b4ea9b9..e5786dc 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java
@@ -68,6 +68,24 @@ } @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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/topLevelFunction.kt");
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java index 8fa1fd2..9074af9 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java
@@ -59,6 +59,24 @@ } @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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/topLevelFunction.kt");
diff --git a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/components/KtAnalysisScopeProviderImpl.kt b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/components/KtAnalysisScopeProviderImpl.kt index 24c4136..715e40d 100644 --- a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/components/KtAnalysisScopeProviderImpl.kt +++ b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/components/KtAnalysisScopeProviderImpl.kt
@@ -23,7 +23,8 @@ class KtAnalysisScopeProviderImpl( override val analysisSession: KtAnalysisSession, - override val token: KtLifetimeToken + override val token: KtLifetimeToken, + private val shadowedScope: GlobalSearchScope ) : KtAnalysisScopeProvider() { private val baseResolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) { @@ -31,13 +32,13 @@ } private val resolveScope by lazy(LazyThreadSafetyMode.PUBLICATION) { - KtAnalysisScopeProviderResolveScope(baseResolveScope, analysisSession.useSiteModule) + KtAnalysisScopeProviderResolveScope(baseResolveScope, analysisSession.useSiteModule, shadowedScope) } override fun getAnalysisScope(): GlobalSearchScope = resolveScope override fun canBeAnalysed(psi: PsiElement): Boolean { - return baseResolveScope.contains(psi) + return (baseResolveScope.contains(psi) && !shadowedScope.contains(psi)) || psi.isFromGeneratedModule() } @@ -49,12 +50,17 @@ private class KtAnalysisScopeProviderResolveScope( private val base: GlobalSearchScope, - private val useSiteModule: KtModule + private val useSiteModule: KtModule, + private val shadowed: GlobalSearchScope, ) : 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) + 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)
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractMultiModuleReferenceResolveWithResolveExtensionTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractMultiModuleReferenceResolveWithResolveExtensionTest.kt index e94af32..4f58b7b 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractMultiModuleReferenceResolveWithResolveExtensionTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractMultiModuleReferenceResolveWithResolveExtensionTest.kt
@@ -5,6 +5,7 @@ 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.resolve.extensions.KtResolveExtensionFile import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider @@ -12,6 +13,12 @@ import org.jetbrains.kotlin.name.FqName abstract class AbstractMultiModuleReferenceResolveWithResolveExtensionTest : AbstractReferenceResolveWithResolveExtensionTest() { - override fun createResolveExtensionProvider(files: List<KtResolveExtensionFile>, packages: Set<FqName>): KtResolveExtensionProvider = - KtMultiModuleResolveExtensionProviderForTest(files, packages) { it is KtSourceModule && it.moduleName == "extendedModule" } + override fun createResolveExtensionProvider( + files: List<KtResolveExtensionFile>, + packages: Set<FqName>, + shadowedScope: GlobalSearchScope, + ): KtResolveExtensionProvider = + KtMultiModuleResolveExtensionProviderForTest(files, packages, shadowedScope) { module -> + module is KtSourceModule && module.moduleName == "extendedModule" + } }
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceResolveWithResolveExtensionTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceResolveWithResolveExtensionTest.kt index 08df27a..9253a97 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceResolveWithResolveExtensionTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceResolveWithResolveExtensionTest.kt
@@ -5,6 +5,9 @@ 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.KtResolveExtensionProviderForTestPreAnalysisHandler import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile @@ -17,17 +20,22 @@ abstract fun createResolveExtensionProvider( files: List<KtResolveExtensionFile>, packages: Set<FqName>, + shadowedScope: GlobalSearchScope, ): KtResolveExtensionProvider override fun configureTest(builder: TestConfigurationBuilder) { super.configureTest(builder) val provider = createResolveExtensionProvider( - listOf( + files = listOf( KtResolveExtensionFileForTests( "extension1.kt", packageName = FqName("generated"), topLevelClassifiersNames = setOf("GeneratedClass1"), - topLevelCallableNames = setOf("generatedTopLevelFunction1", "generatedTopLevelExtensionFunction1"), + topLevelCallableNames = setOf( + "generatedTopLevelFunction1", + "generatedTopLevelExtensionFunction1", + "generatedOverloadedExtensionFunction", + ), fileText = """|package generated | |class GeneratedClass1 { @@ -37,6 +45,8 @@ |fun generatedTopLevelFunction1(): GeneratedClass2 | |fun String.generatedTopLevelExtensionFunction1(boolean: Boolean): Int + | + |fun Any.generatedOverloadedExtensionFunction(): Int """.trimMargin() ), KtResolveExtensionFileForTests( @@ -52,7 +62,14 @@ """.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) { usePreAnalysisHandlers(::KtResolveExtensionProviderForTestPreAnalysisHandler.bind(listOf(provider)))
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractSingleModuleReferenceResolveWithResolveExtensionTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractSingleModuleReferenceResolveWithResolveExtensionTest.kt index fa88458..4b5b3e3 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractSingleModuleReferenceResolveWithResolveExtensionTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractSingleModuleReferenceResolveWithResolveExtensionTest.kt
@@ -5,12 +5,17 @@ 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.resolve.extensions.KtResolveExtensionFile import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider import org.jetbrains.kotlin.name.FqName abstract class AbstractSingleModuleReferenceResolveWithResolveExtensionTest : AbstractReferenceResolveWithResolveExtensionTest() { - override fun createResolveExtensionProvider(files: List<KtResolveExtensionFile>, packages: Set<FqName>): KtResolveExtensionProvider = - KtSingleModuleResolveExtensionProviderForTest(files, packages) + override fun createResolveExtensionProvider( + files: List<KtResolveExtensionFile>, + packages: Set<FqName>, + shadowedScope: GlobalSearchScope, + ): KtResolveExtensionProvider = + KtSingleModuleResolveExtensionProviderForTest(files, packages, shadowedScope) }
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/util/KtResolveExtensionForTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/util/KtResolveExtensionForTest.kt index 183e9e1..ce0ae39 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/util/KtResolveExtensionForTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/util/KtResolveExtensionForTest.kt
@@ -8,6 +8,7 @@ import com.intellij.mock.MockProject import com.intellij.openapi.util.ModificationTracker import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtension import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile @@ -25,20 +26,22 @@ class KtSingleModuleResolveExtensionProviderForTest( private val files: List<KtResolveExtensionFile>, private val packages: Set<FqName>, + private val shadowedScope: GlobalSearchScope, ) : KtResolveExtensionProvider() { override fun provideExtensionsFor(module: KtModule): List<KtResolveExtension> { - return listOf(KtResolveExtensionForTest(files, packages)) + return listOf(KtResolveExtensionForTest(files, packages, shadowedScope)) } } class KtMultiModuleResolveExtensionProviderForTest( private val files: List<KtResolveExtensionFile>, private val packages: Set<FqName>, + private val shadowedScope: GlobalSearchScope, private val hasResolveExtension: (KtModule) -> Boolean, ) : KtResolveExtensionProvider() { override fun provideExtensionsFor(module: KtModule): List<KtResolveExtension> { if (!hasResolveExtension(module)) return emptyList() - return listOf(KtResolveExtensionForTest(files, packages)) + return listOf(KtResolveExtensionForTest(files, packages, shadowedScope)) } } @@ -59,10 +62,12 @@ class KtResolveExtensionForTest( private val files: List<KtResolveExtensionFile>, private val packages: Set<FqName>, + private val shadowedScope: GlobalSearchScope, ) : KtResolveExtension() { override fun getKtFiles(): List<KtResolveExtensionFile> = files override fun getModificationTracker(): ModificationTracker = ModificationTracker.NEVER_CHANGED override fun getContainedPackages(): Set<FqName> = packages + override fun getShadowedScope(): GlobalSearchScope = shadowedScope } class KtResolveExtensionFileForTests(
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java index 726735a..76967f1 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleMultiModuleReferenceResolveWithResolveExtensionTestGenerated.java
@@ -68,6 +68,24 @@ } @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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { runTest("analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/topLevelFunction.kt");
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java index 57c5698..4e746e0 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleSingleModuleReferenceResolveWithResolveExtensionTestGenerated.java
@@ -59,6 +59,24 @@ } @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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { runTest("analysis/analysis-api/testData/resolveExtensions/referenceResolve/topLevelFunction.kt");
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/resolve/extensions/KtResolveExtension.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/resolve/extensions/KtResolveExtension.kt index 6615394..6fbd2e4 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/resolve/extensions/KtResolveExtension.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/resolve/extensions/KtResolveExtension.kt
@@ -6,6 +6,7 @@ package org.jetbrains.kotlin.analysis.api.resolve.extensions import com.intellij.openapi.util.ModificationTracker +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.name.FqName /** @@ -53,4 +54,17 @@ * @see KtResolveExtension */ 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 } \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedDeclaration.kt b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedDeclaration.kt new file mode 100644 index 0000000..efff20c --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedDeclaration.kt
@@ -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() +} \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedJava.kt b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedJava.kt new file mode 100644 index 0000000..a47c38e --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedJava.kt
@@ -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() +} \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.kt b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.kt new file mode 100644 index 0000000..03d24c7 --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.kt
@@ -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() +} \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.txt b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.txt new file mode 100644 index 0000000..fbdbb1d --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.txt
@@ -0,0 +1,2 @@ +Resolved to: +0: (in generated) fun kotlin.Any.generatedOverloadedExtensionFunction(): kotlin.Int \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedDeclaration.kt b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedDeclaration.kt new file mode 100644 index 0000000..94a6ec3 --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedDeclaration.kt
@@ -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() +} \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedJava.kt b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedJava.kt new file mode 100644 index 0000000..36a4a5b --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedJava.kt
@@ -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() +} \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.kt b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.kt new file mode 100644 index 0000000..2354781 --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.kt
@@ -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() +} \ No newline at end of file
diff --git a/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.txt b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.txt new file mode 100644 index 0000000..fbdbb1d --- /dev/null +++ b/analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.txt
@@ -0,0 +1,2 @@ +Resolved to: +0: (in generated) fun kotlin.Any.generatedOverloadedExtensionFunction(): kotlin.Int \ No newline at end of file
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt index 5889958..60c9085 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt
@@ -92,15 +92,3 @@ ) } - -internal fun createJavaSymbolProvider( - firSession: FirSession, - moduleData: LLFirModuleData, - project: Project, - contentScope: GlobalSearchScope -): JavaSymbolProvider { - return JavaSymbolProvider( - firSession, - FirJavaFacadeForSource(firSession, moduleData, project.createJavaClassFinder(contentScope)) - ) -}
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt index 54a7f45..5a7781a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt
@@ -90,9 +90,9 @@ override fun getPackage(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) } 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) { - val combinedScope = GlobalSearchScope.union(providers.map { it.session.llFirModuleData.ktModule.contentScope }) + val combinedScope = GlobalSearchScope.union(providers.map { it.searchScope }) val javaClassFinder = project.createJavaClassFinder(combinedScope) LLFirCombinedJavaSymbolProvider(session, project, providers, javaClassFinder) } else providers.singleOrNull()
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirJavaSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirJavaSymbolProvider.kt new file mode 100644 index 0000000..d1b7eda --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirJavaSymbolProvider.kt
@@ -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)) +) \ No newline at end of file
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt index 22f8a8b..e01eec4 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt
@@ -5,11 +5,11 @@ 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.sessions.LLFirSession import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.SyntheticFirClassProvider 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.ThreadSafeMutableState import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration @@ -29,22 +29,23 @@ @ThreadSafeMutableState internal class LLFirProvider( - val session: FirSession, + val session: LLFirSession, private val moduleComponents: LLFirModuleResolveComponents, - private val declarationProvider: KotlinDeclarationProvider, - packageProvider: KotlinPackageProvider, canContainKotlinPackage: Boolean, + declarationProviderFactory: (GlobalSearchScope) -> KotlinDeclarationProvider?, ) : FirProvider() { override val symbolProvider: FirSymbolProvider = SymbolProvider() private val providerHelper = LLFirProviderHelper( session, moduleComponents.firFileBuilder, - declarationProvider, - packageProvider, canContainKotlinPackage, + declarationProviderFactory, ) + val searchScope: GlobalSearchScope + get() = providerHelper.searchScope + override val isPhasedFirAllowed: Boolean get() = true override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? = @@ -103,9 +104,7 @@ override fun getFirFilesByPackage(fqName: FqName): List<FirFile> = error("Should not be called in FIR IDE") - - override fun getClassNamesInPackage(fqName: FqName): Set<Name> = - declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(fqName) + override fun getClassNamesInPackage(fqName: FqName): Set<Name> = providerHelper.getTopLevelClassNamesInPackage(fqName) @NoMutableState internal inner class SymbolProvider : LLFirKotlinSymbolProvider(session) {
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt index c47e006..2a3b629 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt
@@ -5,18 +5,19 @@ 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.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.sessions.LLFirSession 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.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.builtins.StandardNames 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.getValue import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration @@ -35,27 +36,37 @@ import org.jetbrains.kotlin.psi.KtFile internal class LLFirProviderHelper( - firSession: FirSession, + firSession: LLFirSession, private val firFileBuilder: LLFirFileBuilder, - mainDeclarationProvider: KotlinDeclarationProvider, - mainPackageProvider: KotlinPackageProvider, canContainKotlinPackage: Boolean, + declarationProviderFactory: (GlobalSearchScope) -> KotlinDeclarationProvider? ) { 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( listOfNotNull( - mainDeclarationProvider, + declarationProviderFactory(searchScope), extensionTool?.declarationProvider, ) ) private val packageProvider = CompositeKotlinPackageProvider.create( listOfNotNull( - mainPackageProvider, + firSession.project.createPackageProvider(searchScope), extensionTool?.packageProvider, ) ) + private val allowKotlinPackage = canContainKotlinPackage || firSession.languageVersionSettings.getFlag(AnalysisFlags.allowKotlinPackage) @@ -100,6 +111,11 @@ 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<*>> { if (!allowKotlinPackage && packageFqName.isKotlinPackage()) return emptyList() val callableId = CallableId(packageFqName, name)
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt index 30bee09..23aa10a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt
@@ -8,6 +8,7 @@ import com.intellij.openapi.util.Key import com.intellij.openapi.util.ModificationTracker 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.resolve.extensions.KtResolveExtension import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile @@ -40,6 +41,7 @@ abstract val declarationProvider: LLFirResolveExtensionToolDeclarationProvider abstract val packageProvider: KotlinPackageProvider abstract val packageFilter: LLFirResolveExtensionToolPackageFilter + abstract val shadowedSearchScope: GlobalSearchScope internal abstract val symbolNamesProvider: FirSymbolNamesProvider } @@ -57,13 +59,19 @@ 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 = LLFirResolveExtensionToolDeclarationProvider(fileProvider, session.ktModule) 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) } @@ -310,7 +318,7 @@ .filter { it.getFilePackageName() == packageFqName } } - fun getAllFiles(): Sequence<KtResolveExtensionFile> { + fun getAllFiles(): Sequence<KtResolveExtensionFile> = forbidAnalysis { return extensions .asSequence() .flatMap { it.getKtFiles() }
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt index d0cf098..13e95a5 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt
@@ -15,11 +15,11 @@ 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.project.structure.* +import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createAnnotationResolver 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.util.mergeInto import org.jetbrains.kotlin.analysis.utils.trackers.CompositeModificationTracker import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings @@ -48,7 +48,6 @@ import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration -import org.jetbrains.kotlin.analysis.providers.impl.util.mergeInto @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) internal abstract class LLFirAbstractSessionFactory(protected val project: Project) { @@ -66,7 +65,6 @@ val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) - val contentScope = module.contentScope val dependencies = collectSourceModuleDependencies(module) val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies) @@ -90,10 +88,10 @@ val provider = LLFirProvider( this, components, - FileBasedKotlinDeclarationProvider(module.file), - project.createPackageProvider(contentScope), canContainKotlinPackage = true, - ) + ) { scope -> + scope.createScopedDeclarationProviderForFile(module.file) + } register(FirProvider::class, provider) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) @@ -103,7 +101,7 @@ add(builtinsSession.symbolProvider) }) - val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope) + val javaSymbolProvider = LLFirJavaSymbolProvider(this, moduleData, project, provider.searchScope) register(JavaSymbolProvider::class, javaSymbolProvider) register( @@ -170,10 +168,10 @@ val provider = LLFirProvider( this, components, - if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider, - project.createPackageProvider(module.contentScope), canContainKotlinPackage = true, - ) + ) { scope -> + ktFile?.let { scope.createScopedDeclarationProviderForFile(it) } + } register(FirProvider::class, provider) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) @@ -226,8 +224,6 @@ components.session = session val moduleData = createModuleData(session) - val contentScope = module.contentScope - return session.apply { registerModuleData(moduleData) @@ -240,16 +236,16 @@ val firProvider = LLFirProvider( this, 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 */ canContainKotlinPackage = false, - ) + ) { scope -> + project.createDeclarationProvider(scope, module) + } register(FirProvider::class, firProvider) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) - registerCompilerPluginServices(contentScope, project, module) + registerCompilerPluginServices(firProvider.searchScope, project, module) registerCompilerPluginExtensions(project, module) registerCommonComponentsAfterExtensionsAreConfigured() @@ -273,7 +269,7 @@ } val context = SourceSessionCreationContext( - moduleData, contentScope, firProvider, dependencyProvider, syntheticFunctionInterfaceProvider, + moduleData, firProvider.searchScope, firProvider, dependencyProvider, syntheticFunctionInterfaceProvider, switchableExtensionDeclarationsSymbolProvider, ) additionalSessionConfiguration(context) @@ -320,22 +316,20 @@ registerCommonComponentsAfterExtensionsAreConfigured() registerResolveComponents() - val contentScope = module.contentScope - val firProvider = LLFirProvider( this, components, - project.createDeclarationProvider(contentScope, module), - project.createPackageProvider(contentScope), canContainKotlinPackage = true, - ) + ) { scope -> + project.createDeclarationProvider(scope, module) + } register(FirProvider::class, firProvider) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) // 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(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider) @@ -360,7 +354,7 @@ register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider) register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this)) - val context = LibrarySessionCreationContext(moduleData, contentScope, firProvider, dependencyProvider) + val context = LibrarySessionCreationContext(moduleData, firProvider.searchScope, firProvider, dependencyProvider) additionalSessionConfiguration(context) LLFirSessionConfigurator.configure(this) @@ -504,8 +498,21 @@ ) { mergeInto(destination) { 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) } } } + + /** + * 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 + } }
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt index 1c82bef..6e3cf81 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJvmSessionFactory.kt
@@ -25,7 +25,7 @@ return doCreateSourcesSession(module, FirKotlinScopeProvider(::wrapScopeWithJvmMapped)) { context -> registerCommonJavaComponents(JavaModuleResolver.getInstance(project)) registerJavaSpecificResolveComponents() - val javaSymbolProvider = createJavaSymbolProvider(this, context.moduleData, project, context.contentScope) + val javaSymbolProvider = LLFirJavaSymbolProvider(this, context.moduleData, project, context.contentScope) register(JavaSymbolProvider::class, javaSymbolProvider) register( @@ -50,7 +50,7 @@ return doCreateLibrarySession(module) { context -> registerCommonJavaComponents(JavaModuleResolver.getInstance(project)) registerJavaSpecificResolveComponents() - val javaSymbolProvider = createJavaSymbolProvider(this, context.moduleData, project, context.contentScope) + val javaSymbolProvider = LLFirJavaSymbolProvider(this, context.moduleData, project, context.contentScope) register( FirSymbolProvider::class, LLFirModuleWithDependenciesSymbolProvider(
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedDeserializedSymbolProviderFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedDeserializedSymbolProviderFactory.kt index 1e37eb9..87225c4 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedDeserializedSymbolProviderFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedDeserializedSymbolProviderFactory.kt
@@ -13,7 +13,7 @@ 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.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.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider @@ -56,7 +56,7 @@ FirDeclarationOrigin.Library ) ) - add(createJavaSymbolProvider(session, moduleData, project, scope)) + add(LLFirJavaSymbolProvider(session, moduleData, project, scope)) } } } \ No newline at end of file
diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt index 58148c4..c19ab2c 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt
@@ -25,7 +25,7 @@ // For library and incremental compilation sessions use `KotlinDeserializedJvmSymbolsProvider` // in order to load Kotlin classes as well. //Also used in IDE for loading java classes separately from stub based kotlin classes -class JavaSymbolProvider( +open class JavaSymbolProvider( session: FirSession, private val javaFacade: FirJavaFacade, ) : FirSymbolProvider(session) {