[AA] Add KtResolveExtensionInfoProvider to AA.

This provider is responsible for answering queries related to resolve
extensions. At the moment, this includes retrieving a KtScope with all REx
top-level declarations (moved from KtSymbolFromResolveExtensionProvider), and
retrieving information necessary to supply a GeneratedSourcesFilter for REx
generated code. Future REx-related functions can be added to this interface.

^KT-59329
This commit is contained in:
Justin Paupore
2023-06-14 23:57:38 -07:00
committed by Ilya Kirillov
parent fa0209a322
commit 9f85739599
24 changed files with 1133 additions and 81 deletions
@@ -126,7 +126,7 @@ private constructor(
override val symbolProviderByJavaPsiImpl = KtFirSymbolProviderByJavaPsi(this)
override val resolveExtensionProviderImpl: KtSymbolFromResolveExtensionProvider = KtFirSymbolFromResolveExtensionProvider(this)
override val resolveExtensionInfoProviderImpl: KtResolveExtensionInfoProvider = KtFirResolveExtensionInfoProvider(this)
@Suppress("AnalysisApiMissingLifetimeCheck")
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.components.KtSymbolFromResolveExtensionProvider
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.components.KtResolveExtensionInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtEmptyScope
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
@@ -15,13 +17,17 @@ import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirResolveExtensionTool
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirResolveExtensionToolDeclarationProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.navigationTargetsProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration
internal class KtFirSymbolFromResolveExtensionProvider(
internal class KtFirResolveExtensionInfoProvider(
override val analysisSession: KtFirAnalysisSession,
) : KtSymbolFromResolveExtensionProvider(), KtFirAnalysisSessionComponent {
) : KtResolveExtensionInfoProvider(), KtFirAnalysisSessionComponent {
override val token: KtLifetimeToken
get() = analysisSession.token
@@ -30,6 +36,16 @@ internal class KtFirSymbolFromResolveExtensionProvider(
if (tools.isEmpty()) return KtEmptyScope(token)
return KtFirResolveExtensionScope(analysisSession, tools)
}
@OptIn(KtModuleStructureInternals::class)
override fun isResolveExtensionFile(file: VirtualFile): Boolean =
file.navigationTargetsProvider != null
@OptIn(KtModuleStructureInternals::class)
override fun getResolveExtensionNavigationElements(originalPsi: KtElement): Collection<PsiElement> {
val targetsProvider = originalPsi.containingFile?.virtualFile?.navigationTargetsProvider ?: return emptyList()
return with(targetsProvider) { analysisSession.getNavigationTargets(originalPsi) }
}
}
private class KtFirResolveExtensionScope(
@@ -43,7 +59,7 @@ private class KtFirResolveExtensionScope(
override val token: KtLifetimeToken get() = analysisSession.token
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
gelTopLevelDeclarations(nameFilter) { it.getTopLevelCallables() }
getTopLevelDeclarations(nameFilter) { it.getTopLevelCallables() }
}
override fun getCallableSymbols(names: Collection<Name>): Sequence<KtCallableSymbol> = withValidityAssertion {
@@ -53,7 +69,7 @@ private class KtFirResolveExtensionScope(
}
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> = withValidityAssertion {
gelTopLevelDeclarations(nameFilter) { it.getTopLevelClassifiers() }
getTopLevelDeclarations(nameFilter) { it.getTopLevelClassifiers() }
}
override fun getClassifierSymbols(names: Collection<Name>): Sequence<KtClassifierSymbol> = withValidityAssertion {
@@ -62,7 +78,7 @@ private class KtFirResolveExtensionScope(
return getClassifierSymbols { it in namesSet }
}
private inline fun <D : KtNamedDeclaration, reified S : KtDeclaration> gelTopLevelDeclarations(
private inline fun <D : KtNamedDeclaration, reified S : KtDeclaration> getTopLevelDeclarations(
crossinline nameFilter: KtScopeNameFilter,
crossinline getDeclarationsByProvider: (LLFirResolveExtensionToolDeclarationProvider) -> Sequence<D>,
): Sequence<S> = sequence {
@@ -83,10 +99,14 @@ private class KtFirResolveExtensionScope(
override fun getPackageSymbols(nameFilter: KtScopeNameFilter): Sequence<KtPackageSymbol> = withValidityAssertion {
sequence {
// Only emit package symbols for top-level packages (subpackages of root). This matches the behavior
// of the root-level KtFirPackageScope.
val seenTopLevelPackages = mutableSetOf<Name>()
for (tool in tools) {
for (packageName in tool.packageFilter.getAllPackages()) {
if (!nameFilter(packageName.shortName())) continue
analysisSession.firSymbolBuilder.createPackageSymbol(packageName)
for (packageName in tool.packageFilter.getAllSubPackages(FqName.ROOT)) {
if (seenTopLevelPackages.add(packageName) && nameFilter(packageName)) {
yield(analysisSession.firSymbolBuilder.createPackageSymbol(FqName.ROOT.child(packageName)))
}
}
}
}
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.psiTargetsProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.navigationTargetsProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals
import org.jetbrains.kotlin.psi.KtFile
@@ -21,7 +21,6 @@ interface KtFirReference : KtReference, KtSymbolBasedReference {
fun getResolvedToPsi(analysisSession: KtAnalysisSession, referenceTargetSymbols: Collection<KtSymbol>): Collection<PsiElement> =
with(analysisSession) {
referenceTargetSymbols.flatMap { symbol ->
symbol.getPsiForGeneratedExtensionSymbol()?.let { return@flatMap it }
when (symbol) {
is KtFirSymbol<*> -> getPsiDeclarations(symbol)
else -> listOfNotNull(symbol.psi)
@@ -29,19 +28,6 @@ interface KtFirReference : KtReference, KtSymbolBasedReference {
}
}
context(KtAnalysisSession)
@OptIn(KtModuleStructureInternals::class)
private fun KtSymbol.getPsiForGeneratedExtensionSymbol(): Collection<PsiElement>? {
// TODO symbols generated by KtResolveExtension should probably have their own KtSymbolOrigin, now it's KtSymbolOrigin.SOURCE
if (origin != KtSymbolOrigin.SOURCE) return null
val psi = psi ?: return null
val ktFile = psi.containingFile as? KtFile ?: return null
val psiTargetsProvider = ktFile.virtualFile?.psiTargetsProvider ?: return null
return with(psiTargetsProvider) {
getReferenceTargetsForSymbol(this@getPsiForGeneratedExtensionSymbol)
}
}
fun getResolvedToPsi(analysisSession: KtAnalysisSession): Collection<PsiElement> =
with(analysisSession) {
getResolvedToPsi(analysisSession, resolveToSymbols())
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.fir.test.cases.generated.cases.components.resolveExtensionInfoProvider;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.resolveExtensionInfoProvider.AbstractResolveExtensionInfoProviderTest;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi")
@TestDataPath("$PROJECT_ROOT")
public class FirIdeDependentAnalysisSourceModuleResolveExtensionInfoProviderTestGenerated extends AbstractResolveExtensionInfoProviderTest {
@NotNull
@Override
public AnalysisApiTestConfigurator getConfigurator() {
return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator(
new AnalysisApiTestConfiguratorFactoryData(
FrontendKind.Fir,
TestModuleKind.Source,
AnalysisSessionMode.Dependent,
AnalysisApiMode.Ide
)
);
}
@Test
public void testAllFilesPresentInExtensionScopeWithPsi() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("multipleExtensions.kt")
public void testMultipleExtensions() throws Exception {
runTest("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi/multipleExtensions.kt");
}
@Test
@TestMetadata("singleModule.kt")
public void testSingleModule() throws Exception {
runTest("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi/singleModule.kt");
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.fir.test.cases.generated.cases.components.resolveExtensionInfoProvider;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.resolveExtensionInfoProvider.AbstractResolveExtensionInfoProviderTest;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi")
@TestDataPath("$PROJECT_ROOT")
public class FirIdeNormalAnalysisSourceModuleResolveExtensionInfoProviderTestGenerated extends AbstractResolveExtensionInfoProviderTest {
@NotNull
@Override
public AnalysisApiTestConfigurator getConfigurator() {
return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator(
new AnalysisApiTestConfiguratorFactoryData(
FrontendKind.Fir,
TestModuleKind.Source,
AnalysisSessionMode.Normal,
AnalysisApiMode.Ide
)
);
}
@Test
public void testAllFilesPresentInExtensionScopeWithPsi() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("multipleExtensions.kt")
public void testMultipleExtensions() throws Exception {
runTest("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi/multipleExtensions.kt");
}
@Test
@TestMetadata("singleModule.kt")
public void testSingleModule() throws Exception {
runTest("analysis/analysis-api/testData/components/resolveExtensionInfoProvider/extensionScopeWithPsi/singleModule.kt");
}
}