[AA] KtTypeInfoProvider: introduce fullyExpandedType extension

^KTIJ-23547
^KTIJ-24141
This commit is contained in:
Dmitrii Gridin
2023-01-17 15:11:38 +01:00
committed by Space Team
parent 8ce4c4eba9
commit 09a77d261d
20 changed files with 293 additions and 34 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -60,6 +60,9 @@ internal class KtFe10TypeInfoProvider(
return KotlinBuiltIns.isArrayOrPrimitiveArray(elementType)
}
/** Expanded by default */
override fun fullyExpandedType(type: KtType): KtType = type
private fun KotlinType.isDenotable(): Boolean {
if (this is DefinitelyNotNullType) return false
return constructor.isDenotable &&
@@ -46,6 +46,18 @@ public class Fe10IdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated extends
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("ExpandedParameterType.kt")
public void testExpandedParameterType() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/ExpandedParameterType.kt");
}
@Test
@TestMetadata("ExpandedReturnType.kt")
public void testExpandedReturnType() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/ExpandedReturnType.kt");
}
@Test
@TestMetadata("functionWithReceiverAnnotation.kt")
public void testFunctionWithReceiverAnnotation() throws Exception {
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.resolve.FirSamResolver
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.types.*
internal class KtFirTypeInfoProvider(
@@ -55,4 +56,6 @@ internal class KtFirTypeInfoProvider(
require(type is KtFirType)
return type.coneType.arrayElementType()?.isArrayOrPrimitiveArray == true
}
override fun fullyExpandedType(type: KtType): KtType = type.coneType.fullyExpandedType(analysisSession.useSiteSession).asKtType()
}
@@ -46,6 +46,18 @@ public class FirIdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated extends
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("ExpandedParameterType.kt")
public void testExpandedParameterType() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/ExpandedParameterType.kt");
}
@Test
@TestMetadata("ExpandedReturnType.kt")
public void testExpandedReturnType() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/ExpandedReturnType.kt");
}
@Test
@TestMetadata("functionWithReceiverAnnotation.kt")
public void testFunctionWithReceiverAnnotation() throws Exception {
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.psi.KtClassLikeDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractSubstitutionOverridesUnwrappingTest : AbstractSymbolTest() {
@@ -30,7 +31,7 @@ abstract class AbstractSubstitutionOverridesUnwrappingTest : AbstractSymbolTest(
return SymbolsData(classSymbolUnderCaret.getMemberScope().getAllSymbols().toList())
}
override fun KtAnalysisSession.renderSymbolForComparison(symbol: KtSymbol): String {
override fun KtAnalysisSession.renderSymbolForComparison(symbol: KtSymbol, directives: RegisteredDirectives): String {
return with(DebugSymbolRenderer()) { renderForSubstitutionOverrideUnwrappingTest(symbol) }
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractSymbolByPsiTest : AbstractSymbolTest() {
override val prettyRenderMode: PrettyRenderingMode get() = PrettyRenderingMode.RENDER_SYMBOLS_NESTED
override val defaultRendererOption: PrettyRendererOption get() = PrettyRendererOption.BODY_WITH_MEMBERS
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val allDeclarationSymbols = ktFile.collectDescendantsOfType<KtDeclaration> { it.isValidForSymbolCreation }.map { declaration ->
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -12,9 +12,11 @@ import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.DO_NOT_CHECK_SYMBOL_RESTORE
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.DO_NOT_CHECK_SYMBOL_RESTORE_K1
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.DO_NOT_CHECK_SYMBOL_RESTORE_K2
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.PRETTY_RENDERING_MODE
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.PRETTY_RENDERER_OPTION
import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtDeclarationRenderer
import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForDebug
import org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.KtClassifierBodyRenderer
import org.jetbrains.kotlin.analysis.api.renderer.types.renderers.KtUsualClassTypeRenderer
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithTypeParameters
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
@@ -28,16 +30,16 @@ import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.model.Directive
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.utils.addIfNotNull
import kotlin.test.fail
abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
private val renderer = KtDeclarationRendererForDebug.WITH_QUALIFIED_NAMES
private val defaultRenderer = KtDeclarationRendererForDebug.WITH_QUALIFIED_NAMES
open val prettyRenderMode: PrettyRenderingMode = PrettyRenderingMode.RENDER_SYMBOLS_LINE_BY_LINE
open val defaultRendererOption: PrettyRendererOption? = null
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
@@ -53,11 +55,11 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
val directiveToIgnoreSymbolRestore = directives.doNotCheckSymbolRestoreDirective()
val directiveToIgnoreNonPsiSymbolRestore = directives.doNotCheckNonPsiSymbolRestoreDirective()
val prettyRenderOptions = when (directives.singleOrZeroValue(PRETTY_RENDERING_MODE) ?: prettyRenderMode) {
PrettyRenderingMode.RENDER_SYMBOLS_LINE_BY_LINE -> renderer
PrettyRenderingMode.RENDER_SYMBOLS_NESTED -> renderer.with {
classifierBodyRenderer = KtClassifierBodyRenderer.BODY_WITH_MEMBERS
}
val prettyRenderer = buildList {
addIfNotNull(defaultRendererOption)
addAll(directives[PRETTY_RENDERER_OPTION])
}.fold(defaultRenderer) { acc, prettyRenderingMode ->
prettyRenderingMode.transformation(acc)
}
fun KtAnalysisSession.safePointer(ktSymbol: KtSymbol): PointerWrapper? {
@@ -100,7 +102,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
.map { (symbol, shouldBeRendered) ->
PointerWithRenderedSymbol(
pointer = safePointer(symbol),
rendered = renderSymbolForComparison(symbol),
rendered = renderSymbolForComparison(symbol, directives),
shouldBeRendered = shouldBeRendered,
)
}
@@ -110,10 +112,10 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
PointerWithRenderedSymbol(
safePointer(symbol),
when (symbol) {
is KtDeclarationSymbol -> symbol.render(prettyRenderOptions)
is KtDeclarationSymbol -> symbol.render(prettyRenderer)
is KtFileSymbol -> prettyPrint {
printCollection(symbol.getFileScope().getAllSymbols().asIterable(), separator = "\n\n") {
append(it.render(prettyRenderOptions))
append(it.render(prettyRenderer))
}
}
@@ -137,6 +139,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
ktFile = ktFile,
pointersWithRendered = pointersWithRendered.pointers,
testServices = testServices,
directives = directives,
)
if (directiveToIgnoreSymbolRestore == null) {
@@ -146,6 +149,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
ktFile = ktFile,
pointersWithRendered = pointersWithRendered.pointers,
testServices = testServices,
directives = directives,
)
}
}
@@ -204,6 +208,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
ktFile: KtFile,
pointersWithRendered: List<PointerWithRenderedSymbol>,
testServices: TestServices,
directives: RegisteredDirectives,
) {
var failed = false
val restoredPointers = mutableListOf<KtSymbolPointer<*>>()
@@ -219,7 +224,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
val restored = pointer.restoreSymbol() ?: error("Symbol $expectedRender was not restored")
restoredPointers += pointer
val actualRender = renderSymbolForComparison(restored)
val actualRender = renderSymbolForComparison(restored, directives)
if (shouldBeRendered) {
actualRender
} else {
@@ -285,8 +290,9 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
}
}
protected open fun KtAnalysisSession.renderSymbolForComparison(symbol: KtSymbol): String {
return with(DebugSymbolRenderer(renderExtra = true)) { render(symbol) }
protected open fun KtAnalysisSession.renderSymbolForComparison(symbol: KtSymbol, directives: RegisteredDirectives): String {
val renderExpandedTypes = directives[PRETTY_RENDERER_OPTION].any { it == PrettyRendererOption.FULLY_EXPANDED_TYPES }
return with(DebugSymbolRenderer(renderExtra = true, renderExpandedTypes = renderExpandedTypes)) { render(symbol) }
}
}
@@ -315,12 +321,26 @@ object SymbolTestDirectives : SimpleDirectivesContainer() {
description = "Symbol restoring w/o psi for some symbols in current test is not supported yet in K2",
)
val PRETTY_RENDERING_MODE by enumDirective(description = "Explicit rendering mode") { PrettyRenderingMode.valueOf(it) }
val PRETTY_RENDERER_OPTION by enumDirective(description = "Explicit rendering mode") { PrettyRendererOption.valueOf(it) }
}
enum class PrettyRenderingMode {
RENDER_SYMBOLS_LINE_BY_LINE,
RENDER_SYMBOLS_NESTED,
enum class PrettyRendererOption(val transformation: (KtDeclarationRenderer) -> KtDeclarationRenderer) {
BODY_WITH_MEMBERS(
{ renderer ->
renderer.with {
classifierBodyRenderer = KtClassifierBodyRenderer.BODY_WITH_MEMBERS
}
}
),
FULLY_EXPANDED_TYPES(
{ renderer ->
renderer.with {
typeRenderer = typeRenderer.with {
usualClassTypeRenderer = KtUsualClassTypeRenderer.AS_FULLY_EXPANDED_CLASS_TYPE_WITH_TYPE_ARGUMENTS
}
}
}
)
}
data class SymbolsData(
@@ -46,6 +46,18 @@ public class FirStandaloneNormalAnalysisSourceModuleSingleSymbolByPsiGenerated e
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("ExpandedParameterType.kt")
public void testExpandedParameterType() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/ExpandedParameterType.kt");
}
@Test
@TestMetadata("ExpandedReturnType.kt")
public void testExpandedReturnType() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/ExpandedReturnType.kt");
}
@Test
@TestMetadata("functionWithReceiverAnnotation.kt")
public void testFunctionWithReceiverAnnotation() throws Exception {
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -23,6 +23,7 @@ public abstract class KtTypeInfoProvider : KtAnalysisSessionComponent() {
public abstract fun isDenotable(type: KtType): Boolean
public abstract fun isArrayOrPrimitiveArray(type: KtType): Boolean
public abstract fun isNestedArray(type: KtType): Boolean
public abstract fun fullyExpandedType(type: KtType): KtType
}
public interface KtTypeInfoProviderMixIn : KtAnalysisSessionMixIn {
@@ -102,6 +103,24 @@ public interface KtTypeInfoProviderMixIn : KtAnalysisSessionMixIn {
}
}
/**
* Unwraps type aliases.
* Example:
* ```
* interface Base
*
* typealias FirstAlias = @Anno1 Base
* typealias SecondAlias = @Anno2 FirstAlias
*
* fun foo(): @Anno3 SecondAlias = TODO()
* ```
* The return type of **foo** will be **@Anno3 @Anno2 @Anno1 Base** instead of **@Anno3 SecondAlias**
*/
public val KtType.fullyExpandedType: KtType
get() = withValidityAssertion {
analysisSession.typeInfoProvider.fullyExpandedType(this)
}
/**
* Returns whether the given [KtType] is an array or a primitive array type or not.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -31,4 +31,15 @@ public interface KtUsualClassTypeRenderer {
}
}
public object AS_FULLY_EXPANDED_CLASS_TYPE_WITH_TYPE_ARGUMENTS : KtUsualClassTypeRenderer {
context(KtAnalysisSession, KtTypeRenderer)
override fun renderType(type: KtUsualClassType, printer: PrettyPrinter) {
val fullyExpandedType = type.fullyExpandedType
if (fullyExpandedType is KtUsualClassType) {
AS_CLASS_TYPE_WITH_TYPE_ARGUMENTS.renderType(fullyExpandedType, printer)
} else {
renderType(fullyExpandedType, printer)
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -41,6 +41,7 @@ import kotlin.reflect.jvm.isAccessible
public class DebugSymbolRenderer(
public val renderExtra: Boolean = false,
public val renderTypeByProperties: Boolean = false,
public val renderExpandedTypes: Boolean = false,
) {
context(KtAnalysisSession)
@@ -200,17 +201,20 @@ public class DebugSymbolRenderer(
context(KtAnalysisSession)
private fun PrettyPrinter.renderType(type: KtType) {
val typeToRender = if (renderExpandedTypes) type.fullyExpandedType else type
if (renderTypeByProperties) {
renderByPropertyNames(type)
renderByPropertyNames(typeToRender)
return
}
if (type.annotations.isNotEmpty()) {
renderList(type.annotations, renderSymbolsFully = false)
if (typeToRender.annotations.isNotEmpty()) {
renderList(typeToRender.annotations, renderSymbolsFully = false)
append(' ')
}
when (type) {
when (typeToRender) {
is KtClassErrorType -> append("ERROR_TYPE")
else -> append(type.asStringForDebugging())
else -> append(typeToRender.asStringForDebugging())
}
}
@@ -0,0 +1,46 @@
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: /foo
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isBuiltinFunctionInvoke: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: FINAL
name: foo
origin: SOURCE
receiverParameter: null
returnType: kotlin/Unit
symbolKind: TOP_LEVEL
typeParameters: []
valueParameters: [
KtValueParameterSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
generatedPrimaryConstructorProperty: null
hasDefaultValue: false
isCrossinline: false
isExtension: false
isImplicitLambdaParameter: false
isNoinline: false
isVararg: false
name: param
origin: SOURCE
receiverParameter: null
returnType: SecondAlias
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
]
visibility: Public
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,8 @@
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1
// PRETTY_RENDERER_OPTION: FULLY_EXPANDED_TYPES
interface Base
typealias FirstAlias = Base
typealias SecondAlias = FirstAlias
fun foo<caret>(param: SecondAlias) {}
@@ -0,0 +1 @@
fun foo(param: Base)
@@ -0,0 +1,46 @@
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: /foo
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isBuiltinFunctionInvoke: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: FINAL
name: foo
origin: SOURCE
receiverParameter: null
returnType: kotlin/Unit
symbolKind: TOP_LEVEL
typeParameters: []
valueParameters: [
KtValueParameterSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
generatedPrimaryConstructorProperty: null
hasDefaultValue: false
isCrossinline: false
isExtension: false
isImplicitLambdaParameter: false
isNoinline: false
isVararg: false
name: param
origin: SOURCE
receiverParameter: null
returnType: Base
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
]
visibility: Public
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,26 @@
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: /foo
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isBuiltinFunctionInvoke: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: FINAL
name: foo
origin: SOURCE
receiverParameter: null
returnType: SecondAlias
symbolKind: TOP_LEVEL
typeParameters: []
valueParameters: []
visibility: Public
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,8 @@
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1
// PRETTY_RENDERER_OPTION: FULLY_EXPANDED_TYPES
interface Base
typealias FirstAlias = Base
typealias SecondAlias = FirstAlias
fun foo<caret>(): SecondAlias {}
@@ -0,0 +1 @@
fun foo(): Base
@@ -0,0 +1,26 @@
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: /foo
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isBuiltinFunctionInvoke: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: FINAL
name: foo
origin: SOURCE
receiverParameter: null
returnType: Base
symbolKind: TOP_LEVEL
typeParameters: []
valueParameters: []
visibility: Public
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -1,5 +1,5 @@
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1
// PRETTY_RENDERING_MODE: RENDER_SYMBOLS_NESTED
// PRETTY_RENDERERE_OPTION: BODY_WITH_MEMBERS
annotation class PropertyAnnotation
annotation class FieldAnnotation