[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
@@ -0,0 +1,83 @@
/*
* 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.impl.base.test.cases.components.resolveExtensionInfoProvider
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.scopeProvider.TestScopeRenderer.renderForTests
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.resolve.extensions.KtResolveExtensionTestSupport
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.resolve.extensions.getDescription
import org.jetbrains.kotlin.analysis.api.scopes.KtScope
import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol
import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiBasedTest
import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSingleFileTest
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
abstract class AbstractResolveExtensionInfoProviderTest : AbstractAnalysisApiBasedTest() {
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
KtResolveExtensionTestSupport.configure(builder)
}
private fun List<TestModule>.findMainModule(): TestModule =
singleOrNull()
?: find { it.name == "main" }
?: error("There should either be a single module, or a module named 'main'.")
private fun List<KtFile>.findMainKt(): KtFile =
singleOrNull()
?: find { it.name == "main.kt" }
?: error("There should either be a single Kotlin file in the main module, or a file named 'main.kt'.")
override fun doTestByModuleStructure(moduleStructure: TestModuleStructure, testServices: TestServices) {
val mainModule = moduleStructure.modules.findMainModule()
val ktFiles = testServices.ktModuleProvider.getModuleFiles(mainModule).filterIsInstance<KtFile>()
val mainKt = ktFiles.findMainKt()
analyseForTest(mainKt) {
val resolveExtensionScope = getResolveExtensionScopeWithTopLevelDeclarations()
val actual = resolveExtensionScope.renderSymbolsWithExtendedPsiInfo(pretty = false)
val actualPretty = resolveExtensionScope.renderSymbolsWithExtendedPsiInfo(pretty = true)
testServices.assertions.assertEqualsToTestDataFileSibling(actual)
testServices.assertions.assertEqualsToTestDataFileSibling(actualPretty, extension = ".pretty.txt")
}
}
context(KtAnalysisSession)
private fun KtScope.renderSymbolsWithExtendedPsiInfo(pretty: Boolean) = prettyPrint {
renderForTests(this@renderSymbolsWithExtendedPsiInfo, pretty) { symbol ->
(symbol as? KtDeclarationSymbol)?.getPsiDeclarationInfo()
}
}
context(KtAnalysisSession)
private fun KtDeclarationSymbol.getPsiDeclarationInfo(): String = prettyPrint {
val ktElement = psi as? KtElement
val containingVirtualFile = ktElement?.containingFile?.virtualFile
appendLine("PSI: ${ktElement?.getDescription()} [from ${containingVirtualFile?.name}]")
if (ktElement == null || containingVirtualFile == null) {
return@prettyPrint
}
withIndent {
val isResolveExtensionFile = containingVirtualFile.isResolveExtensionFile
appendLine("From resolve extension: $isResolveExtensionFile")
val navTargets = ktElement.getResolveExtensionNavigationElements()
appendLine("Resolve extension navigation targets: ${navTargets.size}")
withIndent { navTargets.forEach { appendLine(it.toString()) } }
}
}.trimEnd()
}
@@ -12,13 +12,15 @@ 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
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionNavigationTargetsProvider
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionReferencePsiTargetsProvider
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.test.framework.services.environmentManager
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.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.test.services.TestServices
class KtResolveExtensionProviderForTest(
@@ -56,7 +58,7 @@ class KtResolveExtensionFileForTests(
topLevelClassifiersNames: Set<String>,
topLevelCallableNames: Set<String>,
private val fileText: String,
private val psiTargetProvider: KtResolveExtensionReferencePsiTargetsProvider? = null
private val navigationTargetsProvider: KtResolveExtensionNavigationTargetsProvider? = null
) : KtResolveExtensionFile() {
private val topLevelClassifiersNames: Set<Name> = topLevelClassifiersNames.mapTo(mutableSetOf()) { Name.identifier(it) }
@@ -68,12 +70,27 @@ class KtResolveExtensionFileForTests(
override fun buildFileText(): String = fileText
private object EmptyReferencePsiTargetsProvider : KtResolveExtensionReferencePsiTargetsProvider() {
override fun KtAnalysisSession.getReferenceTargetsForSymbol(symbol: KtSymbol): Collection<PsiElement> =
emptyList()
private object ResolveExtensionNavigationTargetProviderForTest : KtResolveExtensionNavigationTargetsProvider() {
override fun KtAnalysisSession.getNavigationTargets(element: KtElement): Collection<PsiElement> =
listOf(KtResolveExtensionNavigationTargetPsiElementForTest(element))
}
override fun createPsiTargetsProvider(): KtResolveExtensionReferencePsiTargetsProvider =
psiTargetProvider ?: EmptyReferencePsiTargetsProvider
override fun createNavigationTargetsProvider(): KtResolveExtensionNavigationTargetsProvider =
navigationTargetsProvider ?: ResolveExtensionNavigationTargetProviderForTest
}
fun KtElement.getDescription(): String = buildString {
val declaration = when (this@getDescription) {
is KtDeclaration -> this@getDescription
else -> {
append("${this@getDescription.javaClass.simpleName} in ")
getStrictParentOfType<KtDeclaration>() ?: containingKtFile
}
}
append("${declaration.javaClass.simpleName} ${declaration.name}")
}
class KtResolveExtensionNavigationTargetPsiElementForTest(val originalElement: KtElement) : PsiElement by originalElement {
override fun toString() = "[Resolve extension navigation target for test for ${originalElement.getDescription()}]"
}