K2: implement annotating record components for @all: use-site target

#KT-73256 Fixed
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxModernJdkCodegenBasedTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxModernJdkCodegenBasedTestGenerated.java
index 0b80f2d..ea75f41 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxModernJdkCodegenBasedTestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxModernJdkCodegenBasedTestGenerated.java
@@ -341,6 +341,12 @@
     @TestDataPath("$PROJECT_ROOT")
     public class Records {
       @Test
+      @TestMetadata("allAnnotation.kt")
+      public void testAllAnnotation() {
+        runTest("compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt");
+      }
+
+      @Test
       public void testAllFilesPresentInRecords() {
         KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxModernJdk/testsWithJava17/records"), Pattern.compile("^(.+)\\.kt$"), null, true);
       }
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxModernJdkCodegenBasedTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxModernJdkCodegenBasedTestGenerated.java
index c978457..d1d9fe7 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxModernJdkCodegenBasedTestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxModernJdkCodegenBasedTestGenerated.java
@@ -341,6 +341,12 @@
     @TestDataPath("$PROJECT_ROOT")
     public class Records {
       @Test
+      @TestMetadata("allAnnotation.kt")
+      public void testAllAnnotation() {
+        runTest("compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt");
+      }
+
+      @Test
       public void testAllFilesPresentInRecords() {
         KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxModernJdk/testsWithJava17/records"), Pattern.compile("^(.+)\\.kt$"), null, true);
       }
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt
index eaf3adc..49b53ac 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt
@@ -5,6 +5,8 @@
 
 package org.jetbrains.kotlin.codegen
 
-fun ClassBuilder.addRecordComponent(name: String, desc: String, signature: String?) {
-    newRecordComponent(name, desc, signature)
+import org.jetbrains.org.objectweb.asm.RecordComponentVisitor
+
+fun ClassBuilder.addRecordComponent(name: String, desc: String, signature: String?): RecordComponentVisitor {
+    return newRecordComponent(name, desc, signature)
 }
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt
index 19159f6..0718106 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt
@@ -9,6 +9,7 @@
 import org.jetbrains.kotlin.builtins.StandardNames
 import org.jetbrains.kotlin.config.LanguageFeature
 import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
 import org.jetbrains.kotlin.fir.*
 import org.jetbrains.kotlin.fir.backend.*
 import org.jetbrains.kotlin.fir.backend.utils.*
@@ -42,6 +43,7 @@
 import org.jetbrains.kotlin.ir.declarations.IrClass
 import org.jetbrains.kotlin.ir.expressions.*
 import org.jetbrains.kotlin.ir.expressions.impl.*
+import org.jetbrains.kotlin.ir.isAnnotationWithAllUseSiteTarget
 import org.jetbrains.kotlin.ir.symbols.*
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.dump
@@ -957,7 +959,11 @@
                         typeArgumentsCount = fullyExpandedConstructorSymbol.typeParameterSymbols.size,
                         constructorTypeArgumentsCount = 0,
                         source = FirAnnotationSourceElement(annotation),
-                    )
+                    ).apply {
+                        if (annotation.useSiteTarget == AnnotationUseSiteTarget.ALL) {
+                            this.isAnnotationWithAllUseSiteTarget = true
+                        }
+                    }
                 }
             }
         }
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxModernJdkCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxModernJdkCodegenTestGenerated.java
index e383b5c..21cefbe 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxModernJdkCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxModernJdkCodegenTestGenerated.java
@@ -342,6 +342,12 @@
     @TestDataPath("$PROJECT_ROOT")
     public class Records {
       @Test
+      @TestMetadata("allAnnotation.kt")
+      public void testAllAnnotation() {
+        runTest("compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt");
+      }
+
+      @Test
       public void testAllFilesPresentInRecords() {
         KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxModernJdk/testsWithJava17/records"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
       }
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxModernJdkCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxModernJdkCodegenTestGenerated.java
index c46eabf..5a51e0e 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxModernJdkCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxModernJdkCodegenTestGenerated.java
@@ -342,6 +342,12 @@
     @TestDataPath("$PROJECT_ROOT")
     public class Records {
       @Test
+      @TestMetadata("allAnnotation.kt")
+      public void testAllAnnotation() {
+        runTest("compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt");
+      }
+
+      @Test
       public void testAllFilesPresentInRecords() {
         KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxModernJdk/testsWithJava17/records"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
       }
diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt
index ba675d3..2475742 100644
--- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt
+++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt
@@ -32,6 +32,7 @@
 import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
 import org.jetbrains.kotlin.ir.declarations.*
 import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.ir.isAnnotationWithAllUseSiteTarget
 import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.*
@@ -78,6 +79,10 @@
                 }
                 continue
             }
+            if (annotated is IrProperty && this is RecordComponentAnnotationCodegen) {
+                if (KotlinTarget.PROPERTY !in applicableTargets) continue
+                if (annotation.isAnnotationWithAllUseSiteTarget != true) continue
+            }
 
             genAnnotation(annotation, null, false)?.let { descriptor ->
                 annotationDescriptorsAlreadyPresent.add(descriptor)
diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt
index a68c23d..548c2b9 100644
--- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt
+++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt
@@ -388,8 +388,12 @@
         }
 
         if (irClass.hasAnnotation(JVM_RECORD_ANNOTATION_FQ_NAME) && !field.isStatic) {
-            // TODO: Write annotations to the component
-            visitor.addRecordComponent(fieldName, fieldType.descriptor, fieldSignature)
+            val rcv = visitor.addRecordComponent(fieldName, fieldType.descriptor, fieldSignature)
+            if (context.config.languageVersionSettings.supportsFeature(LanguageFeature.AnnotationAllUseSiteTarget)) {
+                val recordComponentAnnotationCodegen = RecordComponentAnnotationCodegen(this@ClassCodegen, rcv)
+                // Probably we should filter out non-all and inapplicable annotations
+                field.correspondingPropertySymbol?.owner?.let { recordComponentAnnotationCodegen.genAnnotations(it) }
+            }
         }
     }
 
@@ -636,3 +640,12 @@
 // From `isAnonymousClass` in inlineCodegenUtils.kt
 private val Type.isAnonymousClass: Boolean
     get() = internalName.substringAfterLast("$", "").toIntOrNull() != null
+
+class RecordComponentAnnotationCodegen(
+    classCodegen: ClassCodegen,
+    private val rcv: RecordComponentVisitor,
+) : AnnotationCodegen(classCodegen) {
+    override fun visitAnnotation(descr: String, visible: Boolean): AnnotationVisitor {
+        return rcv.visitAnnotation(descr, visible)
+    }
+}
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AdditionalClassAnnotationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AdditionalClassAnnotationLowering.kt
index 2d5fa28..76c357e 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AdditionalClassAnnotationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AdditionalClassAnnotationLowering.kt
@@ -9,6 +9,9 @@
 import org.jetbrains.kotlin.backend.common.phaser.PhaseDescription
 import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
 import org.jetbrains.kotlin.builtins.StandardNames
+import org.jetbrains.kotlin.config.JvmTarget
+import org.jetbrains.kotlin.config.LanguageFeature
+import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
 import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
 import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
 import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -84,7 +87,7 @@
         if (irClass.hasAnnotation(JvmAnnotationNames.TARGET_ANNOTATION)) return
 
         val targets = irClass.applicableTargetSet() ?: return
-        val javaTargets = targets.mapNotNullTo(HashSet(), ::mapTarget).sortedBy {
+        val javaTargets = targets.mapNotNullTo(HashSet()) { target -> mapTarget(target, irClass) }.sortedBy {
             ElementType.valueOf(it.symbol.owner.name.asString())
         }
 
@@ -109,10 +112,16 @@
             }
     }
 
-    private fun mapTarget(target: KotlinTarget): IrEnumEntry? =
+    private fun mapTarget(target: KotlinTarget, irAnnotationClass: IrClass): IrEnumEntry? =
         when (target) {
             KotlinTarget.TYPE_PARAMETER -> symbols.typeParameterTarget.takeUnless { noNewJavaAnnotationTargets }
             KotlinTarget.TYPE -> symbols.typeUseTarget.takeUnless { noNewJavaAnnotationTargets }
+            KotlinTarget.PROPERTY -> symbols.recordComponentTarget.takeIf {
+                context.config.languageVersionSettings.supportsFeature(LanguageFeature.AnnotationAllUseSiteTarget) &&
+                        context.config.target >= JvmTarget.JVM_16 &&
+                        irAnnotationClass.getAnnotationRetention().let { it == null || it == KotlinRetention.RUNTIME }
+
+            }
             else -> symbols.jvmTargetMap[target]
         }
 
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt
index 7cdfc2d..03dc7d9 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt
@@ -1179,6 +1179,7 @@
 
         val typeParameterTarget = buildEnumEntry(elementTypeEnum, "TYPE_PARAMETER")
         val typeUseTarget = buildEnumEntry(elementTypeEnum, "TYPE_USE")
+        val recordComponentTarget = buildEnumEntry(elementTypeEnum, "RECORD_COMPONENT")
     }
 
     companion object {
diff --git a/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/CommonIrAttributes.kt b/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/CommonIrAttributes.kt
index d8f860a..770be05 100644
--- a/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/CommonIrAttributes.kt
+++ b/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/CommonIrAttributes.kt
@@ -5,6 +5,8 @@
 
 package org.jetbrains.kotlin.ir
 
+import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
+
 /**
  * Original element before inlining. Useful only with IR
  * inliner. `null` if the element wasn't inlined. Unlike [attributeOwnerId], doesn't have the
@@ -12,4 +14,12 @@
  *
  * `null` <=> `this` element wasn't inlined.
  */
-var IrElement.originalBeforeInline: IrElement? by irAttribute(followAttributeOwner = false)
\ No newline at end of file
+var IrElement.originalBeforeInline: IrElement? by irAttribute(followAttributeOwner = false)
+
+/**
+ * For annotation calls, shows if the original annotation has the all: use-site target.
+ * It's necessary for implementation of RECORD_COMPONENT annotating, that should work only in case when we have this use-site target.
+ *
+ * @return true for an annotation with all: use-site target, null otherwise.
+ */
+var IrConstructorCall.isAnnotationWithAllUseSiteTarget: Boolean? by irAttribute(followAttributeOwner = false)
diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt
new file mode 100644
index 0000000..164c5cf
--- /dev/null
+++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt
@@ -0,0 +1,29 @@
+// IGNORE_BACKEND_K1: JVM_IR
+// ISSUE: KT-73256 (not supported in K1)
+// LANGUAGE: +AnnotationAllUseSiteTarget +PropertyParamAnnotationDefaultTargetMode
+
+annotation class My
+
+@Target(AnnotationTarget.FIELD)
+annotation class Your
+
+@JvmRecord
+data class Some(@all:My val x: Int, @My @field:My val y: Int, @all:Your val z: Int)
+
+fun box(): String {
+    val recordComponents = Some::class.java.recordComponents
+
+    if (recordComponents[0].annotations.isEmpty()) {
+        return "FAIL: no record component annotation for '@all:My val x' found"
+    }
+
+    if (recordComponents[1].annotations.isNotEmpty()) {
+        return "FAIL: record component annotation for '@My val y' found, but it should not be so"
+    }
+
+    if (recordComponents[2].annotations.isNotEmpty()) {
+        return "FAIL: record component annotation for '@all:Your val z' found, but it should not be so"
+    }
+
+    return "OK"
+}
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestRestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestRestGenerated.java
index 11932aa..cfcf629 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestRestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestRestGenerated.java
@@ -6438,6 +6438,12 @@
       @TestDataPath("$PROJECT_ROOT")
       public class Records {
         @Test
+        @TestMetadata("allAnnotation.kt")
+        public void testAllAnnotation() {
+          runTest("compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt");
+        }
+
+        @Test
         public void testAllFilesPresentInRecords() {
           KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxModernJdk/testsWithJava17/records"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
         }
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxModernJdkCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxModernJdkCodegenTestGenerated.java
index b554d0c..988f70d 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxModernJdkCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxModernJdkCodegenTestGenerated.java
@@ -342,6 +342,12 @@
     @TestDataPath("$PROJECT_ROOT")
     public class Records {
       @Test
+      @TestMetadata("allAnnotation.kt")
+      public void testAllAnnotation() {
+        runTest("compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt");
+      }
+
+      @Test
       public void testAllFilesPresentInRecords() {
         KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxModernJdk/testsWithJava17/records"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
       }
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxModernJdkCodegenTestGeneratedWithInlineScopes.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxModernJdkCodegenTestGeneratedWithInlineScopes.java
index 20c7a8f..b2457bc 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxModernJdkCodegenTestGeneratedWithInlineScopes.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxModernJdkCodegenTestGeneratedWithInlineScopes.java
@@ -342,6 +342,12 @@
     @TestDataPath("$PROJECT_ROOT")
     public class Records {
       @Test
+      @TestMetadata("allAnnotation.kt")
+      public void testAllAnnotation() {
+        runTest("compiler/testData/codegen/boxModernJdk/testsWithJava17/records/allAnnotation.kt");
+      }
+
+      @Test
       public void testAllFilesPresentInRecords() {
         KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxModernJdk/testsWithJava17/records"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
       }