[Analysis API] add tests for checking KtType internals
This commit is contained in:
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
|
||||||
|
abstract class AbstractTypeByDeclarationReturnTypeTest : AbstractTypeTest() {
|
||||||
|
context(KtAnalysisSession)
|
||||||
|
override fun getType(ktFile: KtFile, module: TestModule, testServices: TestServices): KtType {
|
||||||
|
val declarationAtCaret = testServices.expressionMarkerProvider.getElementOfTypeAtCaret<KtDeclaration>(ktFile)
|
||||||
|
return declarationAtCaret.getReturnKtType()
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer
|
||||||
|
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSingleFileTest
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import org.jetbrains.kotlin.test.services.assertions
|
||||||
|
|
||||||
|
abstract class AbstractTypeTest : AbstractAnalysisApiSingleFileTest() {
|
||||||
|
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
|
||||||
|
val actual = analyseForTest(ktFile.declarations.first()) {
|
||||||
|
val type = getType(ktFile, module, testServices)
|
||||||
|
DebugSymbolRenderer(renderTypeByProperties = true).renderType(type)
|
||||||
|
}
|
||||||
|
testServices.assertions.assertEqualsToTestDataFileSibling(actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
context(KtAnalysisSession)
|
||||||
|
protected abstract fun getType(ktFile: KtFile, module: TestModule, testServices: TestServices): KtType
|
||||||
|
}
|
||||||
+76
-13
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analysis.api.contracts.description.renderKtContractE
|
|||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
|
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossiblyNamedSymbol
|
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossiblyNamedSymbol
|
||||||
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
|
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
|
||||||
|
import org.jetbrains.kotlin.analysis.api.types.KtClassTypeQualifier
|
||||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||||
@@ -28,14 +29,18 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KFunction
|
import kotlin.reflect.KFunction
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KVisibility
|
||||||
import kotlin.reflect.full.*
|
import kotlin.reflect.full.*
|
||||||
|
import kotlin.reflect.jvm.isAccessible
|
||||||
|
|
||||||
public class DebugSymbolRenderer(
|
public class DebugSymbolRenderer(
|
||||||
public val renderExtra: Boolean = false,
|
public val renderExtra: Boolean = false,
|
||||||
|
public val renderTypeByProperties: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
@@ -64,13 +69,17 @@ public class DebugSymbolRenderer(
|
|||||||
.declaredMemberExtensionFunctions
|
.declaredMemberExtensionFunctions
|
||||||
.filter { it.name == "getContainingModule" }
|
.filter { it.name == "getContainingModule" }
|
||||||
.forEach {
|
.forEach {
|
||||||
|
appendLine()
|
||||||
renderFunction(it, renderSymbolsFully = false, this@KtAnalysisSession, symbol)
|
renderFunction(it, renderSymbolsFully = false, this@KtAnalysisSession, symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
KtSymbolInfoProviderMixIn::class.declaredMemberExtensionProperties
|
KtSymbolInfoProviderMixIn::class.declaredMemberExtensionProperties
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { (it.extensionReceiverParameter?.type?.classifier as? KClass<*>)?.isInstance(symbol) == true }
|
.filter { (it.extensionReceiverParameter?.type?.classifier as? KClass<*>)?.isInstance(symbol) == true }
|
||||||
.forEach { renderProperty(it, renderSymbolsFully = false, this@KtAnalysisSession, symbol) }
|
.forEach {
|
||||||
|
appendLine()
|
||||||
|
renderProperty(it, renderSymbolsFully = false, this@KtAnalysisSession, symbol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,29 +89,33 @@ public class DebugSymbolRenderer(
|
|||||||
renderSymbolHeader(symbol)
|
renderSymbolHeader(symbol)
|
||||||
|
|
||||||
withIndent {
|
withIndent {
|
||||||
|
appendLine()
|
||||||
renderProperty(KtCallableSymbol::callableIdIfNonLocal, renderSymbolsFully = false, symbol)
|
renderProperty(KtCallableSymbol::callableIdIfNonLocal, renderSymbolsFully = false, symbol)
|
||||||
if (symbol is KtNamedSymbol) {
|
if (symbol is KtNamedSymbol) {
|
||||||
|
appendLine()
|
||||||
renderProperty(KtNamedSymbol::name, renderSymbolsFully = false, symbol)
|
renderProperty(KtNamedSymbol::name, renderSymbolsFully = false, symbol)
|
||||||
}
|
}
|
||||||
|
appendLine()
|
||||||
renderProperty(KtCallableSymbol::origin, renderSymbolsFully = false, symbol)
|
renderProperty(KtCallableSymbol::origin, renderSymbolsFully = false, symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
private fun PrettyPrinter.renderFunction(function: KFunction<*>, renderSymbolsFully: Boolean, vararg args: Any) {
|
private fun PrettyPrinter.renderFunction(function: KFunction<*>, renderSymbolsFully: Boolean, vararg args: Any) {
|
||||||
appendLine().append(function.name).append(": ")
|
append(function.name).append(": ")
|
||||||
renderFunctionCall(function, renderSymbolsFully, args)
|
renderFunctionCall(function, renderSymbolsFully, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
private fun PrettyPrinter.renderProperty(property: KProperty<*>, renderSymbolsFully: Boolean, vararg args: Any) {
|
private fun PrettyPrinter.renderProperty(property: KProperty<*>, renderSymbolsFully: Boolean, vararg args: Any) {
|
||||||
appendLine().append(property.name).append(": ")
|
append(property.name).append(": ")
|
||||||
renderFunctionCall(property.getter, renderSymbolsFully, args)
|
renderFunctionCall(property.getter, renderSymbolsFully, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
private fun PrettyPrinter.renderFunctionCall(function: KFunction<*>, renderSymbolsFully: Boolean, args: Array<out Any>) {
|
private fun PrettyPrinter.renderFunctionCall(function: KFunction<*>, renderSymbolsFully: Boolean, args: Array<out Any>) {
|
||||||
try {
|
try {
|
||||||
|
function.isAccessible = true
|
||||||
renderValue(function.call(*args), renderSymbolsFully)
|
renderValue(function.call(*args), renderSymbolsFully)
|
||||||
} catch (e: InvocationTargetException) {
|
} catch (e: InvocationTargetException) {
|
||||||
append("Could not render due to ").appendLine(e.cause.toString())
|
append("Could not render due to ").appendLine(e.cause.toString())
|
||||||
@@ -114,18 +127,18 @@ public class DebugSymbolRenderer(
|
|||||||
renderSymbolHeader(symbol)
|
renderSymbolHeader(symbol)
|
||||||
val apiClass = getSymbolApiClass(symbol)
|
val apiClass = getSymbolApiClass(symbol)
|
||||||
withIndent {
|
withIndent {
|
||||||
apiClass.members
|
val members = apiClass.members
|
||||||
.asSequence()
|
|
||||||
.filterIsInstance<KProperty<*>>()
|
.filterIsInstance<KProperty<*>>()
|
||||||
.filter { it.name !in ignoredPropertyNames }
|
.filter { it.name !in ignoredPropertyNames }
|
||||||
.sortedBy { it.name }
|
.sortedBy { it.name }
|
||||||
.forEach { member ->
|
appendLine()
|
||||||
renderProperty(
|
printCollectionIfNotEmpty(members, separator = "\n") { member ->
|
||||||
member,
|
renderProperty(
|
||||||
renderSymbolsFully = member.name == KtValueParameterSymbol::generatedPrimaryConstructorProperty.name,
|
member,
|
||||||
symbol
|
renderSymbolsFully = member.name == KtValueParameterSymbol::generatedPrimaryConstructorProperty.name,
|
||||||
)
|
symbol
|
||||||
}
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +200,10 @@ public class DebugSymbolRenderer(
|
|||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
private fun PrettyPrinter.renderType(type: KtType) {
|
private fun PrettyPrinter.renderType(type: KtType) {
|
||||||
|
if (renderTypeByProperties) {
|
||||||
|
renderByPropertyNames(type)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (type.annotations.isNotEmpty()) {
|
if (type.annotations.isNotEmpty()) {
|
||||||
renderList(type.annotations, renderSymbolsFully = false)
|
renderList(type.annotations, renderSymbolsFully = false)
|
||||||
append(' ')
|
append(' ')
|
||||||
@@ -197,6 +214,22 @@ public class DebugSymbolRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context(KtAnalysisSession)
|
||||||
|
private fun PrettyPrinter.renderByPropertyNames(value: Any) {
|
||||||
|
val members = value::class.members
|
||||||
|
.filter { it.name !in ignoredPropertyNames }
|
||||||
|
.filter { it.visibility != KVisibility.PRIVATE && it.visibility != KVisibility.INTERNAL }
|
||||||
|
.sortedBy { it.name }
|
||||||
|
.filterIsInstance<KProperty<*>>()
|
||||||
|
printCollectionIfNotEmpty(members, separator = "\n") { member ->
|
||||||
|
renderProperty(
|
||||||
|
member,
|
||||||
|
renderSymbolsFully = false,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
private fun PrettyPrinter.renderAnnotationApplication(call: KtAnnotationApplication) {
|
private fun PrettyPrinter.renderAnnotationApplication(call: KtAnnotationApplication) {
|
||||||
renderValue(call.classId, renderSymbolsFully = false)
|
renderValue(call.classId, renderSymbolsFully = false)
|
||||||
@@ -229,6 +262,8 @@ public class DebugSymbolRenderer(
|
|||||||
// Symbol-related values
|
// Symbol-related values
|
||||||
is KtSymbol -> renderSymbolTag(value, renderSymbolsFully)
|
is KtSymbol -> renderSymbolTag(value, renderSymbolsFully)
|
||||||
is KtType -> renderType(value)
|
is KtType -> renderType(value)
|
||||||
|
is KtTypeProjection -> renderTypeProjection(value)
|
||||||
|
is KtClassTypeQualifier -> renderTypeQualifier(value)
|
||||||
is KtAnnotationValue -> renderAnnotationValue(value)
|
is KtAnnotationValue -> renderAnnotationValue(value)
|
||||||
is KtContractEffectDeclaration -> Context(this@KtAnalysisSession, this@renderValue, this@DebugSymbolRenderer)
|
is KtContractEffectDeclaration -> Context(this@KtAnalysisSession, this@renderValue, this@DebugSymbolRenderer)
|
||||||
.renderKtContractEffectDeclaration(value, endWithNewLine = false)
|
.renderKtContractEffectDeclaration(value, endWithNewLine = false)
|
||||||
@@ -256,6 +291,27 @@ public class DebugSymbolRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context(KtAnalysisSession)
|
||||||
|
private fun PrettyPrinter.renderTypeProjection(value: KtTypeProjection) {
|
||||||
|
when (value) {
|
||||||
|
is KtStarTypeProjection -> append("*")
|
||||||
|
is KtTypeArgumentWithVariance -> {
|
||||||
|
if (value.variance != Variance.INVARIANT) {
|
||||||
|
append("${value.variance.label} ")
|
||||||
|
}
|
||||||
|
renderType(value.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context(KtAnalysisSession)
|
||||||
|
private fun PrettyPrinter.renderTypeQualifier(value: KtClassTypeQualifier) {
|
||||||
|
appendLine("qualifier:")
|
||||||
|
withIndent {
|
||||||
|
renderByPropertyNames(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
private fun PrettyPrinter.rendeContextReceiver(receiver: KtContextReceiver) {
|
private fun PrettyPrinter.rendeContextReceiver(receiver: KtContextReceiver) {
|
||||||
append("ContextReceiver(")
|
append("ContextReceiver(")
|
||||||
@@ -335,7 +391,14 @@ public class DebugSymbolRenderer(
|
|||||||
else lines.first() + " ..."
|
else lines.first() + " ..."
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ignoredPropertyNames = setOf("psi", "token")
|
private val ignoredPropertyNames = setOf(
|
||||||
|
"psi",
|
||||||
|
"token",
|
||||||
|
"builder",
|
||||||
|
"coneType",
|
||||||
|
"analysisContext",
|
||||||
|
"fe10Type"
|
||||||
|
)
|
||||||
|
|
||||||
private val symbolImplementationPackageNames = listOf(
|
private val symbolImplementationPackageNames = listOf(
|
||||||
"org.jetbrains.kotlin.analysis.api.fir",
|
"org.jetbrains.kotlin.analysis.api.fir",
|
||||||
|
|||||||
Reference in New Issue
Block a user