From f590e88bdd236a3abdfa0f5946f480b4496cbe75 Mon Sep 17 00:00:00 2001 From: Justin Paupore Date: Mon, 22 May 2023 17:59:47 -0700 Subject: [PATCH] [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 --- .../api/descriptors/KtFe10AnalysisSession.kt | 4 +- .../analysis/api/fir/KtFirAnalysisSession.kt | 21 ++++++- ...olveWithResolveExtensionTestGenerated.java | 18 ++++++ ...olveWithResolveExtensionTestGenerated.java | 18 ++++++ .../components/KtAnalysisScopeProviderImpl.kt | 16 +++-- ...eferenceResolveWithResolveExtensionTest.kt | 11 +++- ...eferenceResolveWithResolveExtensionTest.kt | 23 +++++++- ...eferenceResolveWithResolveExtensionTest.kt | 9 ++- .../test/util/KtResolveExtensionForTest.kt | 9 ++- ...olveWithResolveExtensionTestGenerated.java | 18 ++++++ ...olveWithResolveExtensionTestGenerated.java | 18 ++++++ .../resolve/extensions/KtResolveExtension.kt | 14 +++++ .../shadowedDeclaration.kt | 15 +++++ .../extendedModuleDependency/shadowedJava.kt | 19 ++++++ .../shadowedOverload.kt | 15 +++++ .../shadowedOverload.txt | 2 + .../referenceResolve/shadowedDeclaration.kt | 11 ++++ .../referenceResolve/shadowedJava.kt | 15 +++++ .../referenceResolve/shadowedOverload.kt | 11 ++++ .../referenceResolve/shadowedOverload.txt | 2 + .../structure/sessionFactoryHelpers.kt | 12 ---- .../LLFirCombinedJavaSymbolProvider.kt | 4 +- .../fir/providers/LLFirJavaSymbolProvider.kt | 24 ++++++++ .../level/api/fir/providers/LLFirProvider.kt | 19 +++--- .../api/fir/providers/LLFirProviderHelper.kt | 30 +++++++--- .../extensions/LLFirResolveExtensionTool.kt | 12 +++- .../sessions/LLFirAbstractSessionFactory.kt | 59 +++++++++++-------- .../fir/sessions/LLFirJvmSessionFactory.kt | 4 +- ...bBasedDeserializedSymbolProviderFactory.kt | 4 +- .../kotlin/fir/java/JavaSymbolProvider.kt | 2 +- 30 files changed, 357 insertions(+), 82 deletions(-) create mode 100644 analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedDeclaration.kt create mode 100644 analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedJava.kt create mode 100644 analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.kt create mode 100644 analysis/analysis-api/testData/resolveExtensions/multiModule/referenceResolve/extendedModuleDependency/shadowedOverload.txt create mode 100644 analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedDeclaration.kt create mode 100644 analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedJava.kt create mode 100644 analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.kt create mode 100644 analysis/analysis-api/testData/resolveExtensions/referenceResolve/shadowedOverload.txt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirJavaSymbolProvider.kt 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 10540022c0c..902a0b47eb6 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 @@ class KtFe10AnalysisSession( 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 4704c7b0038..9dcf00cb5b4 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 @@ private constructor( 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 @@ private constructor( internal val firSymbolProvider: FirSymbolProvider get() = useSiteSession.symbolProvider internal val targetPlatform: TargetPlatform get() = useSiteSession.moduleData.platform - val useSiteAnalysisScope: GlobalSearchScope = analysisScopeProviderImpl.getAnalysisScope() - val extensionTools: List + + val useSiteAnalysisScope: GlobalSearchScope + val useSiteScopeDeclarationProvider: KotlinDeclarationProvider val useSitePackageProvider: KotlinPackageProvider @@ -167,6 +168,20 @@ private constructor( 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 b4ea9b950d4..e5786dc648f 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 @@ -67,6 +67,24 @@ public class FirIdeNormalAnalysisSourceModuleMultiModuleReferenceResolveWithReso 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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { 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 8fa1fd2d260..9074af9d0df 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 @@ -58,6 +58,24 @@ public class FirIdeNormalAnalysisSourceModuleSingleModuleReferenceResolveWithRes 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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { 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 24c41369e5f..715e40d92a6 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 @@ import org.jetbrains.kotlin.psi.psiUtil.contains 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 @@ class KtAnalysisScopeProviderImpl( } 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 @@ class KtAnalysisScopeProviderImpl( 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 e94af32a8ed..4f58b7b08e7 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.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.name.FqName abstract class AbstractMultiModuleReferenceResolveWithResolveExtensionTest : AbstractReferenceResolveWithResolveExtensionTest() { - override fun createResolveExtensionProvider(files: List, packages: Set): KtResolveExtensionProvider = - KtMultiModuleResolveExtensionProviderForTest(files, packages) { it is KtSourceModule && it.moduleName == "extendedModule" } + override fun createResolveExtensionProvider( + files: List, + packages: Set, + 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 08df27a956e..9253a9782be 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 class AbstractReferenceResolveWithResolveExtensionTest : AbstractRefere abstract fun createResolveExtensionProvider( files: List, packages: Set, + 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 @@ abstract class AbstractReferenceResolveWithResolveExtensionTest : AbstractRefere |fun generatedTopLevelFunction1(): GeneratedClass2 | |fun String.generatedTopLevelExtensionFunction1(boolean: Boolean): Int + | + |fun Any.generatedOverloadedExtensionFunction(): Int """.trimMargin() ), KtResolveExtensionFileForTests( @@ -52,7 +62,14 @@ abstract class AbstractReferenceResolveWithResolveExtensionTest : AbstractRefere """.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 fa88458f1c5..4b5b3e39309 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, packages: Set): KtResolveExtensionProvider = - KtSingleModuleResolveExtensionProviderForTest(files, packages) + override fun createResolveExtensionProvider( + files: List, + packages: Set, + 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 183e9e1c5b6..ce0ae399c73 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 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.util 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 @@ import org.jetbrains.kotlin.test.services.TestServices class KtSingleModuleResolveExtensionProviderForTest( private val files: List, private val packages: Set, + private val shadowedScope: GlobalSearchScope, ) : KtResolveExtensionProvider() { override fun provideExtensionsFor(module: KtModule): List { - return listOf(KtResolveExtensionForTest(files, packages)) + return listOf(KtResolveExtensionForTest(files, packages, shadowedScope)) } } class KtMultiModuleResolveExtensionProviderForTest( private val files: List, private val packages: Set, + private val shadowedScope: GlobalSearchScope, private val hasResolveExtension: (KtModule) -> Boolean, ) : KtResolveExtensionProvider() { override fun provideExtensionsFor(module: KtModule): List { if (!hasResolveExtension(module)) return emptyList() - return listOf(KtResolveExtensionForTest(files, packages)) + return listOf(KtResolveExtensionForTest(files, packages, shadowedScope)) } } @@ -59,10 +62,12 @@ class KtResolveExtensionProviderForTestPreAnalysisHandler( class KtResolveExtensionForTest( private val files: List, private val packages: Set, + private val shadowedScope: GlobalSearchScope, ) : KtResolveExtension() { override fun getKtFiles(): List = files override fun getModificationTracker(): ModificationTracker = ModificationTracker.NEVER_CHANGED override fun getContainedPackages(): Set = 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 726735a7e9c..76967f1c4e1 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 @@ -67,6 +67,24 @@ public class FirStandaloneNormalAnalysisSourceModuleMultiModuleReferenceResolveW 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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { 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 57c5698d984..4e746e053f2 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 @@ -58,6 +58,24 @@ public class FirStandaloneNormalAnalysisSourceModuleSingleModuleReferenceResolve 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 @TestMetadata("topLevelFunction.kt") public void testTopLevelFunction() throws Exception { 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 6615394a6b1..6fbd2e4d85a 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 @@ public abstract class KtResolveExtension { * @see KtResolveExtension */ public abstract fun getContainedPackages(): Set + + /** + * 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 00000000000..efff20c908e --- /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.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 00000000000..a47c38e0782 --- /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 = 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 00000000000..03d24c7e154 --- /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".generatedOverloadedExtensionFunction() +} \ 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 00000000000..fbdbb1d6982 --- /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 00000000000..94a6ec38473 --- /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.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 00000000000..36a4a5bee60 --- /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 = 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 00000000000..2354781ef6d --- /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".generatedOverloadedExtensionFunction() +} \ 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 00000000000..fbdbb1d6982 --- /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 5889958932f..60c9085d26a 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 LLFirSourcesSession.registerCompilerPluginServices( ) } - -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 54a7f45a624..5a7781ad26b 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 @@ internal class LLFirCombinedJavaSymbolProvider private constructor( override fun getPackage(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) } companion object { - fun merge(session: FirSession, project: Project, providers: List): FirSymbolProvider? = + fun merge(session: FirSession, project: Project, providers: List): 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 00000000000..d1b7eda4135 --- /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 22f8a8b1918..e01eec49874 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 @@ import org.jetbrains.kotlin.psi.KtProperty @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 @@ internal class LLFirProvider( override fun getFirFilesByPackage(fqName: FqName): List = error("Should not be called in FIR IDE") - - override fun getClassNamesInPackage(fqName: FqName): Set = - declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(fqName) + override fun getClassNamesInPackage(fqName: FqName): Set = 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 c47e00687fa..2a3b629d1d1 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.KtClassLikeDeclaration 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 @@ internal class LLFirProviderHelper( return classifierByClassId.getValue(classId, classLikeDeclaration) } + fun getTopLevelClassNamesInPackage(packageFqName: FqName): Set { + if (!allowKotlinPackage && packageFqName.isKotlinPackage()) return emptySet() + return declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) + } + fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List> { 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 30bee09ee7a..23aa10a3b93 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 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions 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 class LLFirResolveExtensionTool : FirSessionComponent { 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 @@ internal class LLFirNonEmptyResolveExtensionTool( 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 @@ internal class LLFirResolveExtensionsFileProvider( .filter { it.getFilePackageName() == packageFqName } } - fun getAllFiles(): Sequence { + fun getAllFiles(): Sequence = 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 d0cf098b358..13e95a5d7bf 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.LLFirModuleResolveCompone 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.compiler.plugin.FirScriptingSamWithReceive 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje components.session = session val moduleData = createModuleData(session) - val contentScope = module.contentScope - return session.apply { registerModuleData(moduleData) @@ -240,16 +236,16 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje } val context = SourceSessionCreationContext( - moduleData, contentScope, firProvider, dependencyProvider, syntheticFunctionInterfaceProvider, + moduleData, firProvider.searchScope, firProvider, dependencyProvider, syntheticFunctionInterfaceProvider, switchableExtensionDeclarationsSymbolProvider, ) additionalSessionConfiguration(context) @@ -320,22 +316,20 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje 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 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje ) { mergeInto(destination) { merge { LLFirCombinedKotlinSymbolProvider.merge(session, project, it) } - merge { LLFirCombinedJavaSymbolProvider.merge(session, project, it) } + merge { LLFirCombinedJavaSymbolProvider.merge(session, project, it) } merge { 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 1c82bef1fef..6e3cf8150eb 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 @@ internal class LLFirJvmSessionFactory(project: Project) : LLFirAbstractSessionFa 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 @@ internal class LLFirJvmSessionFactory(project: Project) : LLFirAbstractSessionFa 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 1e37eb9287f..87225c458aa 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 com.intellij.psi.search.GlobalSearchScope 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 @@ class JvmStubBasedDeserializedSymbolProviderFactory : JvmFirDeserializedSymbolPr 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 58148c475b1..c19ab2c2a7c 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 @@ import org.jetbrains.kotlin.name.Name // 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) {