[Tests] Move stub info extraction for test into a separate utility
KTIJ-28668
This commit is contained in:
committed by
Space Team
parent
f6a35ef0e5
commit
604dec7a87
+1
-142
@@ -5,158 +5,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.decompiler.stub.files
|
package org.jetbrains.kotlin.analysis.decompiler.stub.files
|
||||||
|
|
||||||
import com.intellij.psi.stubs.StubElement
|
|
||||||
import com.intellij.util.indexing.FileContentImpl
|
import com.intellij.util.indexing.FileContentImpl
|
||||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinClsStubBuilder
|
import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinClsStubBuilder
|
||||||
import org.jetbrains.kotlin.contracts.description.*
|
|
||||||
import org.jetbrains.kotlin.psi.KtProjectionKind
|
|
||||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
abstract class AbstractAdditionalStubInfoTest : AbstractDecompiledClassTest() {
|
abstract class AbstractAdditionalStubInfoTest : AbstractDecompiledClassTest() {
|
||||||
fun runTest(testDirectory: String) {
|
fun runTest(testDirectory: String) {
|
||||||
val testDirectoryPath = Paths.get(testDirectory)
|
val testDirectoryPath = Paths.get(testDirectory)
|
||||||
val testData = TestData.createFromDirectory(testDirectoryPath)
|
val testData = TestData.createFromDirectory(testDirectoryPath)
|
||||||
val stub = KotlinClsStubBuilder().buildFileStub(FileContentImpl.createByFile(getClassFileToDecompile(testData, false)))!!
|
val stub = KotlinClsStubBuilder().buildFileStub(FileContentImpl.createByFile(getClassFileToDecompile(testData, false)))!!
|
||||||
val builder = StringBuilder()
|
KotlinTestUtils.assertEqualsToFile(testData.getExpectedFile(useK2ToCompileCode), extractAdditionalStubInfo(stub))
|
||||||
extractAdditionInfo(stub, builder, 0)
|
|
||||||
KotlinTestUtils.assertEqualsToFile(testData.getExpectedFile(useK2ToCompileCode), builder.toString())
|
|
||||||
testData.checkIfIdentical(useK2ToCompileCode)
|
testData.checkIfIdentical(useK2ToCompileCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractAdditionInfo(stub: StubElement<*>, builder: StringBuilder, level: Int) {
|
|
||||||
builder.append(stub.toString())
|
|
||||||
when (stub) {
|
|
||||||
is KotlinUserTypeStubImpl -> {
|
|
||||||
val upperBound = stub.upperBound
|
|
||||||
if (upperBound != null) {
|
|
||||||
builder.append(" ft: ")
|
|
||||||
appendFlexibleTypeInfo(builder, upperBound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KotlinFunctionStubImpl -> {
|
|
||||||
val contract = stub.contract
|
|
||||||
if (contract != null) {
|
|
||||||
for (element in contract) {
|
|
||||||
builder.append("\n" + " ".repeat(level)).append("effect:")
|
|
||||||
element.accept(KotlinContractRenderer(builder), null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KotlinPropertyStubImpl -> {
|
|
||||||
val initializer = stub.constantInitializer
|
|
||||||
if (initializer != null) {
|
|
||||||
builder.append("\n").append(" ".repeat(level)).append("initializer: ${initializer.value}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KotlinAnnotationEntryStubImpl -> {
|
|
||||||
val arguments = stub.valueArguments
|
|
||||||
if (arguments != null) {
|
|
||||||
builder
|
|
||||||
.append("\n")
|
|
||||||
.append(" ".repeat(level))
|
|
||||||
.append("valueArguments: ")
|
|
||||||
.append(arguments.entries.joinToString(", ", "(", ")") { "${it.key.asString()} = ${it.value}" })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KotlinParameterStubImpl -> {
|
|
||||||
stub.functionTypeParameterName?.let { builder.append(" paramNameByAnnotation: ").append(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (child in stub.childrenStubs) {
|
|
||||||
builder.append("\n").append(" ".repeat(level))
|
|
||||||
extractAdditionInfo(child, builder, level + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun appendFlexibleTypeInfo(builder: StringBuilder, typeBean: KotlinTypeBean) {
|
|
||||||
when (typeBean) {
|
|
||||||
is KotlinClassTypeBean -> {
|
|
||||||
builder.append(typeBean.classId.asFqNameString())
|
|
||||||
val arguments = typeBean.arguments
|
|
||||||
if (arguments.isNotEmpty()) {
|
|
||||||
builder.append("<")
|
|
||||||
arguments.forEachIndexed { index, arg ->
|
|
||||||
if (index > 0) builder.append(", ")
|
|
||||||
if (arg.projectionKind != KtProjectionKind.NONE) {
|
|
||||||
builder.append(arg.projectionKind.name)
|
|
||||||
}
|
|
||||||
if (arg.projectionKind != KtProjectionKind.STAR) {
|
|
||||||
appendFlexibleTypeInfo(builder, arg.type!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder.append(">")
|
|
||||||
}
|
|
||||||
if (typeBean.nullable) {
|
|
||||||
builder.append("?")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KotlinTypeParameterTypeBean -> {
|
|
||||||
builder.append(typeBean.typeParameterName)
|
|
||||||
if (typeBean.nullable) {
|
|
||||||
builder.append("?")
|
|
||||||
}
|
|
||||||
if (typeBean.definitelyNotNull) {
|
|
||||||
builder.append(" & Any")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is KotlinFlexibleTypeBean -> {
|
|
||||||
appendFlexibleTypeInfo(builder, typeBean.lowerBound)
|
|
||||||
builder.append(" .. ")
|
|
||||||
appendFlexibleTypeInfo(builder, typeBean.upperBound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinContractRenderer(private val buffer: StringBuilder) : KtContractDescriptionVisitor<Unit, Nothing?, KotlinTypeBean, Nothing?>() {
|
|
||||||
override fun visitConditionalEffectDeclaration(conditionalEffect: KtConditionalEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
conditionalEffect.effect.accept(this, data)
|
|
||||||
buffer.append(" -> ")
|
|
||||||
conditionalEffect.condition.accept(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitReturnsEffectDeclaration(returnsEffect: KtReturnsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
buffer.append("Returns(")
|
|
||||||
returnsEffect.value.accept(this, data)
|
|
||||||
buffer.append(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
buffer.append("CallsInPlace(")
|
|
||||||
callsEffect.valueParameterReference.accept(this, data)
|
|
||||||
buffer.append(", ${callsEffect.kind})")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: KtBinaryLogicExpression<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
binaryLogicExpression.left.accept(this, data)
|
|
||||||
buffer.append(" ${binaryLogicExpression.kind.token} ")
|
|
||||||
binaryLogicExpression.right.accept(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitLogicalNot(logicalNot: KtLogicalNot<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
logicalNot.arg.accept(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitIsInstancePredicate(isInstancePredicate: KtIsInstancePredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
isInstancePredicate.arg.accept(this, data)
|
|
||||||
buffer.append(" ${if (isInstancePredicate.isNegated) "!" else ""}is ${isInstancePredicate.type}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitIsNullPredicate(isNullPredicate: KtIsNullPredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
isNullPredicate.arg.accept(this, data)
|
|
||||||
buffer.append(" ${if (isNullPredicate.isNegated) "!=" else "=="} null")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitConstantDescriptor(constantReference: KtConstantReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
buffer.append(constantReference.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitValueParameterReference(valueParameterReference: KtValueParameterReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
|
||||||
buffer.append("param(").append(valueParameterReference.parameterIndex).append(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.decompiler.stub.files
|
||||||
|
|
||||||
|
import com.intellij.psi.stubs.StubElement
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
|
import org.jetbrains.kotlin.psi.KtProjectionKind
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||||
|
|
||||||
|
fun extractAdditionalStubInfo(stub: StubElement<*>): String {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
extractAdditionInfo(stub, builder, 0)
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractAdditionInfo(stub: StubElement<*>, builder: StringBuilder, level: Int) {
|
||||||
|
builder.append(stub.toString())
|
||||||
|
when (stub) {
|
||||||
|
is KotlinUserTypeStubImpl -> {
|
||||||
|
val upperBound = stub.upperBound
|
||||||
|
if (upperBound != null) {
|
||||||
|
builder.append(" ft: ")
|
||||||
|
appendFlexibleTypeInfo(builder, upperBound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KotlinFunctionStubImpl -> {
|
||||||
|
val contract = stub.contract
|
||||||
|
if (contract != null) {
|
||||||
|
for (element in contract) {
|
||||||
|
builder.append("\n" + " ".repeat(level)).append("effect:")
|
||||||
|
element.accept(KotlinContractRenderer(builder), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KotlinPropertyStubImpl -> {
|
||||||
|
val initializer = stub.constantInitializer
|
||||||
|
if (initializer != null) {
|
||||||
|
builder.append("\n").append(" ".repeat(level)).append("initializer: ${initializer.value}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KotlinAnnotationEntryStubImpl -> {
|
||||||
|
val arguments = stub.valueArguments
|
||||||
|
if (arguments != null) {
|
||||||
|
builder
|
||||||
|
.append("\n")
|
||||||
|
.append(" ".repeat(level))
|
||||||
|
.append("valueArguments: ")
|
||||||
|
.append(arguments.entries.joinToString(", ", "(", ")") { "${it.key.asString()} = ${it.value}" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KotlinParameterStubImpl -> {
|
||||||
|
stub.functionTypeParameterName?.let { builder.append(" paramNameByAnnotation: ").append(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (child in stub.childrenStubs) {
|
||||||
|
builder.append("\n").append(" ".repeat(level))
|
||||||
|
extractAdditionInfo(child, builder, level + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun appendFlexibleTypeInfo(builder: StringBuilder, typeBean: KotlinTypeBean) {
|
||||||
|
when (typeBean) {
|
||||||
|
is KotlinClassTypeBean -> {
|
||||||
|
builder.append(typeBean.classId.asFqNameString())
|
||||||
|
val arguments = typeBean.arguments
|
||||||
|
if (arguments.isNotEmpty()) {
|
||||||
|
builder.append("<")
|
||||||
|
arguments.forEachIndexed { index, arg ->
|
||||||
|
if (index > 0) builder.append(", ")
|
||||||
|
if (arg.projectionKind != KtProjectionKind.NONE) {
|
||||||
|
builder.append(arg.projectionKind.name)
|
||||||
|
}
|
||||||
|
if (arg.projectionKind != KtProjectionKind.STAR) {
|
||||||
|
appendFlexibleTypeInfo(builder, arg.type!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.append(">")
|
||||||
|
}
|
||||||
|
if (typeBean.nullable) {
|
||||||
|
builder.append("?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KotlinTypeParameterTypeBean -> {
|
||||||
|
builder.append(typeBean.typeParameterName)
|
||||||
|
if (typeBean.nullable) {
|
||||||
|
builder.append("?")
|
||||||
|
}
|
||||||
|
if (typeBean.definitelyNotNull) {
|
||||||
|
builder.append(" & Any")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is KotlinFlexibleTypeBean -> {
|
||||||
|
appendFlexibleTypeInfo(builder, typeBean.lowerBound)
|
||||||
|
builder.append(" .. ")
|
||||||
|
appendFlexibleTypeInfo(builder, typeBean.upperBound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinContractRenderer(private val buffer: StringBuilder) : KtContractDescriptionVisitor<Unit, Nothing?, KotlinTypeBean, Nothing?>() {
|
||||||
|
override fun visitConditionalEffectDeclaration(conditionalEffect: KtConditionalEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
conditionalEffect.effect.accept(this, data)
|
||||||
|
buffer.append(" -> ")
|
||||||
|
conditionalEffect.condition.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturnsEffectDeclaration(returnsEffect: KtReturnsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append("Returns(")
|
||||||
|
returnsEffect.value.accept(this, data)
|
||||||
|
buffer.append(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append("CallsInPlace(")
|
||||||
|
callsEffect.valueParameterReference.accept(this, data)
|
||||||
|
buffer.append(", ${callsEffect.kind})")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: KtBinaryLogicExpression<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
binaryLogicExpression.left.accept(this, data)
|
||||||
|
buffer.append(" ${binaryLogicExpression.kind.token} ")
|
||||||
|
binaryLogicExpression.right.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLogicalNot(logicalNot: KtLogicalNot<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
logicalNot.arg.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsInstancePredicate(isInstancePredicate: KtIsInstancePredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
isInstancePredicate.arg.accept(this, data)
|
||||||
|
buffer.append(" ${if (isInstancePredicate.isNegated) "!" else ""}is ${isInstancePredicate.type}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsNullPredicate(isNullPredicate: KtIsNullPredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
isNullPredicate.arg.accept(this, data)
|
||||||
|
buffer.append(" ${if (isNullPredicate.isNegated) "!=" else "=="} null")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstantDescriptor(constantReference: KtConstantReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append(constantReference.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitValueParameterReference(valueParameterReference: KtValueParameterReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append("param(").append(valueParameterReference.parameterIndex).append(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user