@@ -9,22 +9,29 @@ import com.semmle.extractor.java.OdasaOutput
99import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
1010import org.jetbrains.kotlin.backend.common.lower.parents
1111import org.jetbrains.kotlin.backend.common.pop
12+ import org.jetbrains.kotlin.backend.jvm.ir.getAnnotationRetention
13+ import org.jetbrains.kotlin.builtins.StandardNames
1214import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
1315import org.jetbrains.kotlin.config.JvmAnalysisFlags
1416import org.jetbrains.kotlin.descriptors.*
17+ import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
18+ import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
1519import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
1620import org.jetbrains.kotlin.ir.IrElement
1721import org.jetbrains.kotlin.ir.IrStatement
1822import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
23+ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
1924import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
2025import org.jetbrains.kotlin.ir.declarations.*
2126import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
2227import org.jetbrains.kotlin.ir.expressions.*
23- import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
24- import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
28+ import org.jetbrains.kotlin.ir.expressions.impl.*
2529import org.jetbrains.kotlin.ir.symbols.*
2630import org.jetbrains.kotlin.ir.types.*
31+ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
2732import org.jetbrains.kotlin.ir.util.*
33+ import org.jetbrains.kotlin.load.java.JvmAbi
34+ import org.jetbrains.kotlin.load.java.JvmAnnotationNames
2835import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
2936import org.jetbrains.kotlin.load.java.structure.JavaClass
3037import org.jetbrains.kotlin.load.java.structure.JavaMethod
@@ -34,7 +41,9 @@ import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
3441import org.jetbrains.kotlin.name.FqName
3542import org.jetbrains.kotlin.types.Variance
3643import org.jetbrains.kotlin.util.OperatorNameConventions
44+ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
3745import java.io.Closeable
46+ import java.lang.annotation.ElementType
3847import java.util.*
3948import kotlin.collections.ArrayList
4049
@@ -458,12 +467,16 @@ open class KotlinFileExtractor(
458467 extractDeclInitializers(c.declarations, false ) { Pair (blockId, obinitId) }
459468 }
460469
461- private fun extractAnnotations (c : IrAnnotationContainer , parent : Label <out DbExprparent >) {
462- for ((idx, constructorCall: IrConstructorCall ) in c. annotations.sortedBy { v -> v.type.classFqName?.asString() }.withIndex()) {
470+ private fun extractAnnotations (annotations : List < IrConstructorCall > , parent : Label <out DbExprparent >) {
471+ for ((idx, constructorCall: IrConstructorCall ) in annotations.sortedBy { v -> v.type.classFqName?.asString() }.withIndex()) {
463472 extractAnnotation(constructorCall, parent, idx)
464473 }
465474 }
466475
476+ private fun extractAnnotations (c : IrAnnotationContainer , parent : Label <out DbExprparent >) {
477+ extractAnnotations(c.annotations, parent)
478+ }
479+
467480 private fun extractAnnotation (
468481 constructorCall : IrConstructorCall ,
469482 parent : Label <out DbExprparent >,
@@ -559,6 +572,175 @@ open class KotlinFileExtractor(
559572 }
560573 }
561574
575+ private val javaAnnotationTargetElementType by lazy { referenceExternalClass(" java.lang.annotation.ElementType" ) }
576+
577+ private val javaAnnotationTarget by lazy { referenceExternalClass(" java.lang.annotation.Target" ) }
578+
579+ // Taken from AdditionalClassAnnotationLowering.kt
580+ private fun getApplicableTargetSet (c : IrClass ): Set <KotlinTarget >? {
581+ val targetEntry = c.getAnnotation(StandardNames .FqNames .target) ? : return null
582+ return loadAnnotationTargets(targetEntry)
583+ }
584+
585+ // Taken from AdditionalClassAnnotationLowering.kt
586+ private fun loadAnnotationTargets (targetEntry : IrConstructorCall ): Set <KotlinTarget >? {
587+ val valueArgument = targetEntry.getValueArgument(0 ) as ? IrVararg ? : return null
588+ return valueArgument.elements.filterIsInstance<IrGetEnumValue >().mapNotNull {
589+ KotlinTarget .valueOrNull(it.symbol.owner.name.asString())
590+ }.toSet()
591+ }
592+
593+
594+ private fun findEnumEntry (c : IrClass , name : String ) =
595+ c.declarations.filterIsInstance<IrEnumEntry >().find { it.name.asString() == name }
596+
597+ // Adapted from JvmSymbols.kt
598+ private val jvm6TargetMap by lazy {
599+ javaAnnotationTargetElementType?.let {
600+ val etMethod = findEnumEntry(it, " METHOD" )
601+ mapOf (
602+ KotlinTarget .CLASS to findEnumEntry(it, " TYPE" ),
603+ KotlinTarget .ANNOTATION_CLASS to findEnumEntry(it, " ANNOTATION_TYPE" ),
604+ KotlinTarget .CONSTRUCTOR to findEnumEntry(it, " CONSTRUCTOR" ),
605+ KotlinTarget .LOCAL_VARIABLE to findEnumEntry(it, " LOCAL_VARIABLE" ),
606+ KotlinTarget .FUNCTION to etMethod,
607+ KotlinTarget .PROPERTY_GETTER to etMethod,
608+ KotlinTarget .PROPERTY_SETTER to etMethod,
609+ KotlinTarget .FIELD to findEnumEntry(it, " FIELD" ),
610+ KotlinTarget .VALUE_PARAMETER to findEnumEntry(it, " PARAMETER" )
611+ )
612+ }
613+ }
614+
615+ // Adapted from JvmSymbols.kt
616+ private val jvm8TargetMap by lazy {
617+ javaAnnotationTargetElementType?.let {
618+ jvm6TargetMap?.let { j6Map ->
619+ j6Map + mapOf (
620+ KotlinTarget .TYPE_PARAMETER to findEnumEntry(it, " TYPE_PARAMETER" ),
621+ KotlinTarget .TYPE to findEnumEntry(it, " TYPE_USE" )
622+ )
623+ }
624+ }
625+ }
626+
627+ // TODO: find out if we can spot when we're building for JVM <= 7 and omit the Java 8-only targets in that case.
628+ private fun getAnnotationTargetMap () = jvm8TargetMap
629+
630+ // Adapted from AdditionalClassAnnotationLowering.kt
631+ private fun generateTargetAnnotation (c : IrClass ): IrConstructorCall ? {
632+ if (c.hasAnnotation(JvmAnnotationNames .TARGET_ANNOTATION ))
633+ return null
634+ val elementType = javaAnnotationTargetElementType ? : return null
635+ val targetType = javaAnnotationTarget ? : return null
636+ val targetConstructor = targetType.declarations.firstIsInstanceOrNull<IrConstructor >() ? : return null
637+ val targets = getApplicableTargetSet(c) ? : return null
638+ val annotationTargetMap = getAnnotationTargetMap() ? : return null
639+
640+ val javaTargets = targets.mapNotNullTo(HashSet ()) { annotationTargetMap[it] }.sortedBy {
641+ ElementType .valueOf(it.symbol.owner.name.asString())
642+ }
643+ val vararg = IrVarargImpl (
644+ UNDEFINED_OFFSET , UNDEFINED_OFFSET ,
645+ type = pluginContext.irBuiltIns.arrayClass.typeWith(elementType.defaultType),
646+ varargElementType = elementType.defaultType
647+ )
648+ for (target in javaTargets) {
649+ vararg.elements.add(
650+ IrGetEnumValueImpl (
651+ UNDEFINED_OFFSET , UNDEFINED_OFFSET , elementType.defaultType, target.symbol
652+ )
653+ )
654+ }
655+
656+ return IrConstructorCallImpl .fromSymbolOwner(
657+ UNDEFINED_OFFSET , UNDEFINED_OFFSET , targetConstructor.returnType, targetConstructor.symbol, 0
658+ ).apply {
659+ putValueArgument(0 , vararg)
660+ }
661+ }
662+
663+ private val javaAnnotationRetention by lazy { referenceExternalClass(" java.lang.annotation.Retention" ) }
664+ private val javaAnnotationRetentionPolicy by lazy { referenceExternalClass(" java.lang.annotation.RetentionPolicy" ) }
665+ private val javaAnnotationRetentionPolicyRuntime by lazy { javaAnnotationRetentionPolicy?.let { findEnumEntry(it, " RUNTIME" ) } }
666+
667+ private val annotationRetentionMap by lazy {
668+ javaAnnotationRetentionPolicy?.let {
669+ mapOf (
670+ KotlinRetention .SOURCE to findEnumEntry(it, " SOURCE" ),
671+ KotlinRetention .BINARY to findEnumEntry(it, " CLASS" ),
672+ KotlinRetention .RUNTIME to javaAnnotationRetentionPolicyRuntime
673+ )
674+ }
675+ }
676+
677+ // Taken from AdditionalClassAnnotationLowering.kt
678+ private fun generateRetentionAnnotation (irClass : IrClass ): IrConstructorCall ? {
679+ if (irClass.hasAnnotation(JvmAnnotationNames .RETENTION_ANNOTATION ))
680+ return null
681+ val retentionMap = annotationRetentionMap ? : return null
682+ val kotlinRetentionPolicy = irClass.getAnnotationRetention()
683+ val javaRetentionPolicy = kotlinRetentionPolicy?.let { retentionMap[it] } ? : javaAnnotationRetentionPolicyRuntime ? : return null
684+ val retentionPolicyType = javaAnnotationRetentionPolicy ? : return null
685+ val retentionType = javaAnnotationRetention ? : return null
686+ val targetConstructor = retentionType.declarations.firstIsInstanceOrNull<IrConstructor >() ? : return null
687+
688+ return IrConstructorCallImpl .fromSymbolOwner(
689+ UNDEFINED_OFFSET , UNDEFINED_OFFSET , targetConstructor.returnType, targetConstructor.symbol, 0
690+ ).apply {
691+ putValueArgument(
692+ 0 ,
693+ IrGetEnumValueImpl (
694+ UNDEFINED_OFFSET , UNDEFINED_OFFSET , retentionPolicyType.defaultType, javaRetentionPolicy.symbol
695+ )
696+ )
697+ }
698+ }
699+
700+ private val javaAnnotationRepeatable by lazy { referenceExternalClass(" java.lang.annotation.Repeatable" ) }
701+
702+ // Taken from AdditionalClassAnnotationLowering.kt
703+ private fun generateRepeatableAnnotation (irClass : IrClass ): IrConstructorCall ? {
704+ if (! irClass.hasAnnotation(StandardNames .FqNames .repeatable) ||
705+ irClass.hasAnnotation(JvmAnnotationNames .REPEATABLE_ANNOTATION )
706+ ) return null
707+
708+ val repeatableConstructor = javaAnnotationRepeatable?.declarations?.firstIsInstanceOrNull<IrConstructor >() ? : return null
709+
710+ val containerClass =
711+ irClass.declarations.singleOrNull {
712+ it is IrClass && it.name.asString() == JvmAbi .REPEATABLE_ANNOTATION_CONTAINER_NAME
713+ } as IrClass ? ? : return null
714+ val containerReference = IrClassReferenceImpl (
715+ UNDEFINED_OFFSET , UNDEFINED_OFFSET , pluginContext.irBuiltIns.kClassClass.typeWith(containerClass.defaultType),
716+ containerClass.symbol, containerClass.defaultType
717+ )
718+ return IrConstructorCallImpl .fromSymbolOwner(
719+ UNDEFINED_OFFSET , UNDEFINED_OFFSET , repeatableConstructor.returnType, repeatableConstructor.symbol, 0
720+ ).apply {
721+ putValueArgument(0 , containerReference)
722+ }
723+ }
724+
725+ private val javaAnnotationDocumented by lazy { referenceExternalClass(" java.lang.annotation.Documented" ) }
726+
727+ // Taken from AdditionalClassAnnotationLowering.kt
728+ private fun generateDocumentedAnnotation (irClass : IrClass ): IrConstructorCall ? {
729+ if (! irClass.hasAnnotation(StandardNames .FqNames .mustBeDocumented) ||
730+ irClass.hasAnnotation(JvmAnnotationNames .DOCUMENTED_ANNOTATION )
731+ ) return null
732+
733+ val documentedConstructor = javaAnnotationDocumented?.declarations?.firstIsInstanceOrNull<IrConstructor >() ? : return null
734+
735+ return IrConstructorCallImpl .fromSymbolOwner(
736+ UNDEFINED_OFFSET , UNDEFINED_OFFSET , documentedConstructor.returnType, documentedConstructor.symbol, 0
737+ )
738+ }
739+
740+ private fun generateJavaMetaAnnotations (c : IrClass ) =
741+ // This is essentially AdditionalClassAnnotationLowering adapted to run outside the backend.
742+ listOfNotNull(generateTargetAnnotation(c), generateRetentionAnnotation(c), generateRepeatableAnnotation(c), generateDocumentedAnnotation(c))
743+
562744 fun extractClassSource (c : IrClass , extractDeclarations : Boolean , extractStaticInitializer : Boolean , extractPrivateMembers : Boolean , extractFunctionBodies : Boolean ): Label <out DbClassorinterface > {
563745 with (" class source" , c) {
564746 DeclarationStackAdjuster (c).use {
@@ -640,7 +822,13 @@ open class KotlinFileExtractor(
640822
641823 linesOfCode?.linesOfCodeInDeclaration(c, id)
642824
643- extractAnnotations(c, id)
825+ val additionalAnnotations =
826+ if (c.kind == ClassKind .ANNOTATION_CLASS && c.origin != IrDeclarationOrigin .IR_EXTERNAL_JAVA_DECLARATION_STUB )
827+ generateJavaMetaAnnotations(c)
828+ else
829+ listOf ()
830+
831+ extractAnnotations(c.annotations + additionalAnnotations, id)
644832
645833 if (extractFunctionBodies && ! c.isAnonymousObject && ! c.isLocal)
646834 externalClassExtractor.writeStubTrapFile(c)
0 commit comments