@@ -9,22 +9,29 @@ import com.semmle.extractor.java.OdasaOutput
9
9
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
10
10
import org.jetbrains.kotlin.backend.common.lower.parents
11
11
import org.jetbrains.kotlin.backend.common.pop
12
+ import org.jetbrains.kotlin.backend.jvm.ir.getAnnotationRetention
13
+ import org.jetbrains.kotlin.builtins.StandardNames
12
14
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
13
15
import org.jetbrains.kotlin.config.JvmAnalysisFlags
14
16
import org.jetbrains.kotlin.descriptors.*
17
+ import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
18
+ import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
15
19
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
16
20
import org.jetbrains.kotlin.ir.IrElement
17
21
import org.jetbrains.kotlin.ir.IrStatement
18
22
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
23
+ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
19
24
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
20
25
import org.jetbrains.kotlin.ir.declarations.*
21
26
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
22
27
import 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.*
25
29
import org.jetbrains.kotlin.ir.symbols.*
26
30
import org.jetbrains.kotlin.ir.types.*
31
+ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
27
32
import org.jetbrains.kotlin.ir.util.*
33
+ import org.jetbrains.kotlin.load.java.JvmAbi
34
+ import org.jetbrains.kotlin.load.java.JvmAnnotationNames
28
35
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
29
36
import org.jetbrains.kotlin.load.java.structure.JavaClass
30
37
import org.jetbrains.kotlin.load.java.structure.JavaMethod
@@ -34,7 +41,9 @@ import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
34
41
import org.jetbrains.kotlin.name.FqName
35
42
import org.jetbrains.kotlin.types.Variance
36
43
import org.jetbrains.kotlin.util.OperatorNameConventions
44
+ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
37
45
import java.io.Closeable
46
+ import java.lang.annotation.ElementType
38
47
import java.util.*
39
48
import kotlin.collections.ArrayList
40
49
@@ -458,12 +467,16 @@ open class KotlinFileExtractor(
458
467
extractDeclInitializers(c.declarations, false ) { Pair (blockId, obinitId) }
459
468
}
460
469
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()) {
463
472
extractAnnotation(constructorCall, parent, idx)
464
473
}
465
474
}
466
475
476
+ private fun extractAnnotations (c : IrAnnotationContainer , parent : Label <out DbExprparent >) {
477
+ extractAnnotations(c.annotations, parent)
478
+ }
479
+
467
480
private fun extractAnnotation (
468
481
constructorCall : IrConstructorCall ,
469
482
parent : Label <out DbExprparent >,
@@ -559,6 +572,175 @@ open class KotlinFileExtractor(
559
572
}
560
573
}
561
574
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
+
562
744
fun extractClassSource (c : IrClass , extractDeclarations : Boolean , extractStaticInitializer : Boolean , extractPrivateMembers : Boolean , extractFunctionBodies : Boolean ): Label <out DbClassorinterface > {
563
745
with (" class source" , c) {
564
746
DeclarationStackAdjuster (c).use {
@@ -640,7 +822,13 @@ open class KotlinFileExtractor(
640
822
641
823
linesOfCode?.linesOfCodeInDeclaration(c, id)
642
824
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)
644
832
645
833
if (extractFunctionBodies && ! c.isAnonymousObject && ! c.isLocal)
646
834
externalClassExtractor.writeStubTrapFile(c)
0 commit comments