[cls] include annotation arguments in cls stubs

^ KTIJ-24666
this would allow to build fir based on stubs,
do not keep ProtoBuf in memory and
search in decompiled code by stubs
This commit is contained in:
Anna Kozlova
2023-04-13 12:15:23 +02:00
parent f0af7c4228
commit 7ee648a4f5
19 changed files with 452 additions and 168 deletions
@@ -5,25 +5,27 @@
package org.jetbrains.kotlin.analysis.decompiler.stub.file
import org.jetbrains.kotlin.analysis.decompiler.stub.AnnotationWithArgs
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.psi.stubs.impl.createConstantValue
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
import org.jetbrains.kotlin.serialization.deserialization.*
class AnnotationLoaderForStubBuilderImpl(
private val protocol: SerializerExtensionProtocol
) : AnnotationLoader<ClassId> {
) : AnnotationLoader<AnnotationWithArgs> {
override fun loadClassAnnotations(container: ProtoContainer.Class): List<ClassId> =
container.classProto.getExtension(protocol.classAnnotation).orEmpty().map { container.nameResolver.getClassId(it.id) }
override fun loadClassAnnotations(container: ProtoContainer.Class): List<AnnotationWithArgs> =
container.classProto.getExtension(protocol.classAnnotation).orEmpty()
.map { loadAnnotation(it, container.nameResolver) }
override fun loadCallableAnnotations(
container: ProtoContainer,
proto: MessageLite,
kind: AnnotatedCallableKind
): List<ClassId> {
): List<AnnotationWithArgs> {
val annotations = when (proto) {
is ProtoBuf.Constructor -> proto.getExtension(protocol.constructorAnnotation)
is ProtoBuf.Function -> proto.getExtension(protocol.functionAnnotation)
@@ -35,17 +37,17 @@ class AnnotationLoaderForStubBuilderImpl(
}
else -> error("Unknown message: $proto")
}.orEmpty()
return annotations.map { container.nameResolver.getClassId(it.id) }
return annotations.map { loadAnnotation(it, container.nameResolver) }
}
override fun loadPropertyBackingFieldAnnotations(container: ProtoContainer, proto: ProtoBuf.Property): List<ClassId> =
override fun loadPropertyBackingFieldAnnotations(container: ProtoContainer, proto: ProtoBuf.Property): List<AnnotationWithArgs> =
emptyList()
override fun loadPropertyDelegateFieldAnnotations(container: ProtoContainer, proto: ProtoBuf.Property): List<ClassId> =
override fun loadPropertyDelegateFieldAnnotations(container: ProtoContainer, proto: ProtoBuf.Property): List<AnnotationWithArgs> =
emptyList()
override fun loadEnumEntryAnnotations(container: ProtoContainer, proto: ProtoBuf.EnumEntry): List<ClassId> =
proto.getExtension(protocol.enumEntryAnnotation).orEmpty().map { container.nameResolver.getClassId(it.id) }
override fun loadEnumEntryAnnotations(container: ProtoContainer, proto: ProtoBuf.EnumEntry): List<AnnotationWithArgs> =
proto.getExtension(protocol.enumEntryAnnotation).orEmpty().map { loadAnnotation(it, container.nameResolver) }
override fun loadValueParameterAnnotations(
container: ProtoContainer,
@@ -53,21 +55,26 @@ class AnnotationLoaderForStubBuilderImpl(
kind: AnnotatedCallableKind,
parameterIndex: Int,
proto: ProtoBuf.ValueParameter
): List<ClassId> =
proto.getExtension(protocol.parameterAnnotation).orEmpty().map { container.nameResolver.getClassId(it.id) }
): List<AnnotationWithArgs> =
proto.getExtension(protocol.parameterAnnotation).orEmpty().map { loadAnnotation(it, container.nameResolver) }
override fun loadExtensionReceiverParameterAnnotations(
container: ProtoContainer,
proto: MessageLite,
kind: AnnotatedCallableKind
): List<ClassId> = emptyList()
): List<AnnotationWithArgs> = emptyList()
override fun loadTypeAnnotations(
proto: ProtoBuf.Type,
nameResolver: NameResolver
): List<ClassId> =
proto.getExtension(protocol.typeAnnotation).orEmpty().map { nameResolver.getClassId(it.id) }
): List<AnnotationWithArgs> =
proto.getExtension(protocol.typeAnnotation).orEmpty().map { loadAnnotation(it, nameResolver) }
override fun loadTypeParameterAnnotations(proto: ProtoBuf.TypeParameter, nameResolver: NameResolver): List<ClassId> =
proto.getExtension(protocol.typeParameterAnnotation).orEmpty().map { nameResolver.getClassId(it.id) }
override fun loadTypeParameterAnnotations(proto: ProtoBuf.TypeParameter, nameResolver: NameResolver): List<AnnotationWithArgs> =
proto.getExtension(protocol.typeParameterAnnotation).orEmpty().map { loadAnnotation(it, nameResolver) }
override fun loadAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationWithArgs {
val valueMap = proto.argumentList.associate { nameResolver.getName(it.nameId) to createConstantValue(it.value, nameResolver) }
return AnnotationWithArgs(nameResolver.getClassId(proto.id), valueMap)
}
}
@@ -13,6 +13,8 @@ import com.intellij.psi.stubs.PsiFileStub
import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.SpecialJvmAnnotations
import org.jetbrains.kotlin.analysis.decompiler.stub.*
import org.jetbrains.kotlin.constant.ConstantValue
import org.jetbrains.kotlin.constant.KClassValue
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.*
@@ -28,11 +30,11 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions
import org.jetbrains.kotlin.resolve.constants.ClassLiteralValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.psi.stubs.impl.createConstantValue
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.storage.LockBasedStorageManager
open class KotlinClsStubBuilder : ClsStubBuilder() {
@@ -135,14 +137,16 @@ private class AnnotationLoaderForClassFileStubBuilder(
private val cachedFile: VirtualFile,
private val cachedFileContent: ByteArray,
override val jvmMetadataVersion: JvmMetadataVersion
) : AbstractBinaryClassAnnotationLoader<ClassId, AnnotationLoaderForClassFileStubBuilder.AnnotationsClassIdContainer>(kotlinClassFinder) {
) : AbstractBinaryClassAnnotationLoader<AnnotationWithArgs, AnnotationsContainerWithConstants<AnnotationWithArgs, ConstantValue<*>>>(
kotlinClassFinder
) {
private val storage =
LockBasedStorageManager.NO_LOCKS.createMemoizedFunction<KotlinJvmBinaryClass, AnnotationsClassIdContainer> { kotlinClass ->
LockBasedStorageManager.NO_LOCKS.createMemoizedFunction<KotlinJvmBinaryClass, AnnotationsContainerWithConstants<AnnotationWithArgs, ConstantValue<*>>> { kotlinClass ->
loadAnnotationsAndInitializers(kotlinClass)
}
override fun getAnnotationsContainer(binaryClass: KotlinJvmBinaryClass): AnnotationsClassIdContainer {
override fun getAnnotationsContainer(binaryClass: KotlinJvmBinaryClass): AnnotationsContainerWithConstants<AnnotationWithArgs, ConstantValue<*>> {
return storage(binaryClass)
}
@@ -153,34 +157,20 @@ private class AnnotationLoaderForClassFileStubBuilder(
return null
}
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): ClassId = nameResolver.getClassId(proto.id)
override fun loadAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationWithArgs {
val args = proto.argumentList.associate { nameResolver.getName(it.nameId) to createConstantValue(it.value, nameResolver) }
return AnnotationWithArgs(nameResolver.getClassId(proto.id), args)
}
override fun loadAnnotation(
annotationClassId: ClassId, source: SourceElement, result: MutableList<ClassId>
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
if (annotationClassId != SpecialJvmAnnotations.JAVA_LANG_ANNOTATION_REPEATABLE) {
result += annotationClassId
return null
}
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor {
private val arguments = mutableMapOf<Name, ConstantValue<*>>()
override fun visitClassLiteral(name: Name?, value: ClassLiteralValue) {
if (name != null)
arguments[name] = KClassValue(value)
}
annotationClassId: ClassId, source: SourceElement, result: MutableList<AnnotationWithArgs>
): KotlinJvmBinaryClass.AnnotationArgumentVisitor {
return object : AnnotationMemberDefaultValueVisitor() {
override fun visitEnd() {
if (!isRepeatableWithImplicitContainer(annotationClassId, arguments)) {
result.add(annotationClassId)
if (!isRepeatableWithImplicitContainer(annotationClassId, args)) {
result.add(AnnotationWithArgs(annotationClassId, args))
}
}
override fun visit(name: Name?, value: Any?) = Unit
override fun visitEnum(name: Name?, enumClassId: ClassId, enumEntryName: Name) = Unit
override fun visitArray(name: Name?): KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor? = null
override fun visitAnnotation(name: Name?, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? = null
}
}
@@ -188,12 +178,13 @@ private class AnnotationLoaderForClassFileStubBuilder(
if (annotationClassId != SpecialJvmAnnotations.JAVA_LANG_ANNOTATION_REPEATABLE) return false
val containerKClassValue = arguments[JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME] as? KClassValue ?: return false
val normalClass = containerKClassValue.value as? KClassValue.Value.NormalClass ?: return false
return isImplicitRepeatableContainer(normalClass.classId)
return isImplicitRepeatableContainer((containerKClassValue.value as KClassValue.Value.NormalClass).classId)
}
private fun loadAnnotationsAndInitializers(kotlinClass: KotlinJvmBinaryClass): AnnotationsClassIdContainer {
val memberAnnotations = HashMap<MemberSignature, MutableList<ClassId>>()
private fun loadAnnotationsAndInitializers(kotlinClass: KotlinJvmBinaryClass): AnnotationsContainerWithConstants<AnnotationWithArgs, ConstantValue<*>> {
val memberAnnotations = HashMap<MemberSignature, MutableList<AnnotationWithArgs>>()
val propertyConstants = HashMap<MemberSignature, ConstantValue<*>>()
val annotationParametersDefaultValues = HashMap<MemberSignature, ConstantValue<*>>()
kotlinClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor {
override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor {
@@ -226,7 +217,7 @@ private class AnnotationLoaderForClassFileStubBuilder(
}
open inner class MemberAnnotationVisitor(protected val signature: MemberSignature) : KotlinJvmBinaryClass.AnnotationVisitor {
private val result = ArrayList<ClassId>()
private val result = ArrayList<AnnotationWithArgs>()
override fun visitAnnotation(classId: ClassId, source: SourceElement): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
return loadAnnotationIfNotSpecial(classId, source, result)
@@ -240,10 +231,10 @@ private class AnnotationLoaderForClassFileStubBuilder(
}
}, getCachedFileContent(kotlinClass))
return AnnotationsClassIdContainer(memberAnnotations)
return AnnotationsContainerWithConstants(
memberAnnotations,
propertyConstants,
annotationParametersDefaultValues
)
}
class AnnotationsClassIdContainer(
override val memberAnnotations: Map<MemberSignature, List<ClassId>>
) : AbstractBinaryClassAnnotationLoader.AnnotationsContainer<ClassId>()
}
}
@@ -0,0 +1,109 @@
package test
import test.E.E1
import kotlin.reflect.KClass
const val CONSTANT = 12
class AnnotationValues {
@Simple(
12,
12L,
12,
3.3,
f = 3.3F,
c = 'a',
b1 = true,
b2 = false
)
class WithSimple
@StringLiteral("some", "", "H$CONSTANT")
class WithStringLiteral
@EnumLiteral(E1, E.E2, e3 = test.E.E2)
class WithEnumLiteral
@VarArg(1, 2, 3)
class WithVarArg
@Arrays(
[1, 2, 3],
[1L],
[],
[2.2],
['a'],
[true, false]
)
class WithArrays
@ClassLiteral(
WithClassLiteral::class,
String::class
)
class WithClassLiteral<T>
@Outer("value", nested = Nested(12, "nested value"))
class WithNested
}
annotation class Simple(
val i: Int,
val l: Long,
val b: Byte,
val d: Double,
val f: Float,
val c: Char,
val b1: Boolean,
val b2: Boolean
)
annotation class StringLiteral(
val s1: String,
val s2: String,
val s3: String
)
enum class E {
E1, E2
}
annotation class EnumLiteral(
val e1: E,
val e2: E,
val e3: E
)
annotation class VarArg(
vararg val v: Int
)
annotation class Arrays(
val ia: IntArray,
val la: LongArray,
val fa: FloatArray,
val da: DoubleArray,
val ca: CharArray,
val ba: BooleanArray
)
annotation class ClassLiteral(
val c1: KClass<*>,
val c2: KClass<*>
)
annotation class Nested(
val i: Int,
val s: String
)
annotation class Outer(
val some: String,
val nested: Nested
)
@@ -0,0 +1,110 @@
PsiJetFileStubImpl[package=test]
KotlinStub$PACKAGE_DIRECTIVE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$IMPORT_LIST
KotlinStub$CLASS[classId=test/AnnotationValues, fqName=test.AnnotationValues, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=AnnotationValues, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=AnnotationValues]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
KotlinStub$CLASS[classId=test/AnnotationValues.WithArrays, fqName=test.AnnotationValues.WithArrays, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=WithArrays, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=Arrays]
valueArguments: (ia = [1, 2, 3], la = [1.toLong()], fa = [], da = [2.2.toDouble()], ca = [\u0061 ('a')], ba = [true, false])
KotlinStub$CONSTRUCTOR_CALLEE
KotlinStub$TYPE_REFERENCE
KotlinStub$USER_TYPE
KotlinStub$USER_TYPE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$REFERENCE_EXPRESSION[referencedName=Arrays]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=WithArrays]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
KotlinStub$CLASS[classId=test/AnnotationValues.WithClassLiteral, fqName=test.AnnotationValues.WithClassLiteral, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=WithClassLiteral, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=ClassLiteral]
valueArguments: (c1 = NormalClass(value=test/AnnotationValues.WithClassLiteral), c2 = NormalClass(value=kotlin/String))
KotlinStub$CONSTRUCTOR_CALLEE
KotlinStub$TYPE_REFERENCE
KotlinStub$USER_TYPE
KotlinStub$USER_TYPE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$REFERENCE_EXPRESSION[referencedName=ClassLiteral]
KotlinStub$TYPE_PARAMETER_LIST
KotlinStub$TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=T]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=WithClassLiteral]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
KotlinStub$CLASS[classId=test/AnnotationValues.WithEnumLiteral, fqName=test.AnnotationValues.WithEnumLiteral, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=WithEnumLiteral, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=EnumLiteral]
valueArguments: (e1 = E.E1, e2 = E.E2, e3 = E.E2)
KotlinStub$CONSTRUCTOR_CALLEE
KotlinStub$TYPE_REFERENCE
KotlinStub$USER_TYPE
KotlinStub$USER_TYPE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$REFERENCE_EXPRESSION[referencedName=EnumLiteral]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=WithEnumLiteral]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
KotlinStub$CLASS[classId=test/AnnotationValues.WithNested, fqName=test.AnnotationValues.WithNested, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=WithNested, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=Outer]
valueArguments: (some = "value", nested = Value(type=KotlinClassTypeBean(classId=test/Nested, arguments=[], nullable=false), argumentsMapping={i=12, s="nested value"}))
KotlinStub$CONSTRUCTOR_CALLEE
KotlinStub$TYPE_REFERENCE
KotlinStub$USER_TYPE
KotlinStub$USER_TYPE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$REFERENCE_EXPRESSION[referencedName=Outer]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=WithNested]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
KotlinStub$CLASS[classId=test/AnnotationValues.WithSimple, fqName=test.AnnotationValues.WithSimple, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=WithSimple, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=Simple]
valueArguments: (i = 12, l = 12.toLong(), b = 12.toByte(), d = 3.3.toDouble(), f = 3.3.toFloat(), c = \u0061 ('a'), b1 = true, b2 = false)
KotlinStub$CONSTRUCTOR_CALLEE
KotlinStub$TYPE_REFERENCE
KotlinStub$USER_TYPE
KotlinStub$USER_TYPE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$REFERENCE_EXPRESSION[referencedName=Simple]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=WithSimple]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
KotlinStub$CLASS[classId=test/AnnotationValues.WithStringLiteral, fqName=test.AnnotationValues.WithStringLiteral, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=WithStringLiteral, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=StringLiteral]
valueArguments: (s1 = "some", s2 = "", s3 = "H12")
KotlinStub$CONSTRUCTOR_CALLEE
KotlinStub$TYPE_REFERENCE
KotlinStub$USER_TYPE
KotlinStub$USER_TYPE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$REFERENCE_EXPRESSION[referencedName=StringLiteral]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=WithStringLiteral]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
KotlinStub$CLASS[classId=test/AnnotationValues.WithVarArg, fqName=test.AnnotationValues.WithVarArg, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=WithVarArg, superNames=[]]
KotlinStub$MODIFIER_LIST[public final]
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=VarArg]
valueArguments: (v = [1, 2, 3])
KotlinStub$CONSTRUCTOR_CALLEE
KotlinStub$TYPE_REFERENCE
KotlinStub$USER_TYPE
KotlinStub$USER_TYPE
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
KotlinStub$REFERENCE_EXPRESSION[referencedName=VarArg]
KotlinStub$PRIMARY_CONSTRUCTOR[fqName=null, hasBody=false, isDelegatedCallToThis=false, isExtension=false, isTopLevel=false, name=WithVarArg]
KotlinStub$MODIFIER_LIST[public]
KotlinStub$VALUE_PARAMETER_LIST
KotlinStub$CLASS_BODY
@@ -50,6 +50,16 @@ abstract class AbstractAdditionalStubInfoTest : AbstractDecompiledClassTest() {
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}" })
}
}
}
for (child in stub.childrenStubs) {
builder.append("\n").append(" ".repeat(level))
@@ -30,6 +30,12 @@ public class AdditionalStubInfoTestGenerated extends AbstractAdditionalStubInfoT
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/AnnotatedFlexibleTypes/");
}
@Test
@TestMetadata("AnnotationValues")
public void testAnnotationValues() throws Exception {
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/AnnotationValues/");
}
@Test
@TestMetadata("Contracts")
public void testContracts() throws Exception {