K2: fix field annotation splitting and frontend checks
Related to KT-57135
This commit is contained in:
committed by
Space Team
parent
37ed7beda0
commit
dc38ce24f7
+12
@@ -39,6 +39,18 @@ public class FirOutOfContentRootLazyBodiesCalculatorTestGenerated extends Abstra
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnField.kt")
|
||||
public void testAnnotationOnField() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnProperty.kt")
|
||||
public void testAnnotationOnProperty() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnProperty.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
|
||||
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
|
||||
|
||||
+12
@@ -39,6 +39,18 @@ public class FirSourceLazyBodiesCalculatorTestGenerated extends AbstractFirSourc
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnField.kt")
|
||||
public void testAnnotationOnField() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnProperty.kt")
|
||||
public void testAnnotationOnProperty() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnProperty.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
|
||||
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
|
||||
|
||||
+6
@@ -6747,6 +6747,12 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/falseSamConversion.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("FieldAnnotationWithClasses.kt")
|
||||
public void testFieldAnnotationWithClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/FieldAnnotationWithClasses.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("immutableName.kt")
|
||||
public void testImmutableName() throws Exception {
|
||||
|
||||
+6
@@ -6747,6 +6747,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/falseSamConversion.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("FieldAnnotationWithClasses.kt")
|
||||
public void testFieldAnnotationWithClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/FieldAnnotationWithClasses.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("immutableName.kt")
|
||||
public void testImmutableName() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FILE: concurrent.kt
|
||||
@R|kotlin/jvm/Volatile|() public final var xx: R|kotlin/Int| = Int(2)
|
||||
field:@R|kotlin/jvm/Volatile|() public final var xx: R|kotlin/Int| = Int(2)
|
||||
public get(): R|kotlin/Int|
|
||||
public set(value: R|kotlin/Int|): R|kotlin/Unit|
|
||||
@R|kotlin/jvm/Synchronized|() public final fun foo(): R|kotlin/Unit| {
|
||||
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
FILE: FieldAnnotationWithClasses.kt
|
||||
public final annotation class Ann : R|kotlin/Annotation| {
|
||||
public constructor(vararg allowedTypes: R|kotlin/Array<out kotlin/reflect/KClass<*>>|): R|Ann| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val allowedTypes: R|kotlin/Array<out kotlin/reflect/KClass<*>>| = R|<local>/allowedTypes|
|
||||
public get(): R|kotlin/Array<out kotlin/reflect/KClass<*>>|
|
||||
|
||||
}
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
local final class Local : R|kotlin/Any| {
|
||||
public constructor(): R|Local| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
field:@FIELD:R|Ann|(allowedTypes = vararg(allowedTypes = <implicitArrayOf>(<getClass>(Q|Some|), <getClass>(Q|Other|)))) public final val x: R|kotlin/Int| = Int(42)
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public final class Some : R|kotlin/Any| {
|
||||
public constructor(): R|Some| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class Other : R|kotlin/Any| {
|
||||
public constructor(): R|Other| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
annotation class Ann(vararg val allowedTypes: KClass<*>)
|
||||
|
||||
fun foo() {
|
||||
class Local {
|
||||
@field:Ann(allowedTypes = [Some::class, Other::class])
|
||||
val x: Int = 42
|
||||
}
|
||||
}
|
||||
|
||||
class Some
|
||||
class Other
|
||||
+6
@@ -6747,6 +6747,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/falseSamConversion.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("FieldAnnotationWithClasses.kt")
|
||||
public void testFieldAnnotationWithClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/FieldAnnotationWithClasses.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("immutableName.kt")
|
||||
public void testImmutableName() throws Exception {
|
||||
|
||||
+6
@@ -6747,6 +6747,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/falseSamConversion.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("FieldAnnotationWithClasses.kt")
|
||||
public void testFieldAnnotationWithClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/FieldAnnotationWithClasses.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("immutableName.kt")
|
||||
public void testImmutableName() throws Exception {
|
||||
|
||||
+3
-2
@@ -39,7 +39,8 @@ import org.jetbrains.kotlin.name.StandardClassIds
|
||||
object FirJvmFieldApplicabilityChecker : FirPropertyChecker() {
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val session = context.session
|
||||
val annotation = declaration.getAnnotationByClassId(JVM_FIELD_ANNOTATION_CLASS_ID, session) ?: return
|
||||
val annotation = declaration.backingField?.getAnnotationByClassId(JVM_FIELD_ANNOTATION_CLASS_ID, session)
|
||||
?: return
|
||||
val containingClassSymbol = declaration.containingClassLookupTag()?.toFirRegularClassSymbol(session)
|
||||
|
||||
val problem = when {
|
||||
@@ -125,7 +126,7 @@ object FirJvmFieldApplicabilityChecker : FirPropertyChecker() {
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.hasJvmFieldAnnotation(session: FirSession): Boolean {
|
||||
return getAnnotationByClassId(JVM_FIELD_ANNOTATION_CLASS_ID, session) != null
|
||||
return backingFieldSymbol?.getAnnotationByClassId(JVM_FIELD_ANNOTATION_CLASS_ID, session) != null
|
||||
}
|
||||
|
||||
private fun isInsideJvmMultifileClassFile(context: CheckerContext): Boolean {
|
||||
|
||||
+2
-4
@@ -199,10 +199,8 @@ object FirJvmStaticChecker : FirBasicDeclarationChecker() {
|
||||
reporter: DiagnosticReporter,
|
||||
targetSource: KtSourceElement?,
|
||||
) {
|
||||
if (
|
||||
declaration is FirProperty && declaration.isConst ||
|
||||
declaration.hasAnnotationNamedAs(StandardClassIds.Annotations.JvmField)
|
||||
) {
|
||||
if (declaration !is FirProperty) return
|
||||
if (declaration.isConst || declaration.backingField?.hasAnnotationNamedAs(StandardClassIds.Annotations.JvmField) == true) {
|
||||
reporter.reportOn(targetSource, FirJvmErrors.JVM_STATIC_ON_CONST_OR_JVM_FIELD, context)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.name.JvmNames.JVM_SYNTHETIC_ANNOTATION_CLASS_ID
|
||||
|
||||
object FirJvmSyntheticApplicabilityChecker : FirPropertyChecker() {
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotation = declaration.delegateFieldSymbol?.getAnnotationByClassId(JVM_SYNTHETIC_ANNOTATION_CLASS_ID, context.session)
|
||||
val annotation = declaration.backingField?.getAnnotationByClassId(JVM_SYNTHETIC_ANNOTATION_CLASS_ID, context.session)
|
||||
if (annotation != null && annotation.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD) {
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.JVM_SYNTHETIC_ON_DELEGATE, context)
|
||||
}
|
||||
|
||||
@@ -587,11 +587,15 @@ fun FirFunctionSymbol<*>.isFunctionForExpectTypeFromCastFeature(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun getActualTargetList(annotated: FirAnnotationContainer): AnnotationTargetList {
|
||||
fun getActualTargetList(container: FirAnnotationContainer): AnnotationTargetList {
|
||||
fun CallableId.isMember(): Boolean {
|
||||
return classId != null || isLocal // TODO: Replace with .containingClass (after fixing)
|
||||
}
|
||||
|
||||
val annotated =
|
||||
if (container is FirBackingField && !container.propertySymbol.hasBackingField) container.propertyIfBackingField
|
||||
else container
|
||||
|
||||
return when (annotated) {
|
||||
is FirRegularClass -> {
|
||||
AnnotationTargetList(
|
||||
|
||||
+9
-5
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
|
||||
import org.jetbrains.kotlin.fir.delegatedWrapperData
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.packageFqName
|
||||
@@ -118,8 +119,8 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
|
||||
propertySymbol.resolvedReceiverTypeRef == null && propertySymbol.resolvedContextReceivers.isEmpty()
|
||||
|
||||
val (hint, type) = when (annotation.useSiteTarget) {
|
||||
FIELD -> "fields" to ((declaration as? FirProperty)?.backingField?.returnTypeRef ?: return)
|
||||
PROPERTY_DELEGATE_FIELD -> "delegate fields" to ((declaration as? FirProperty)?.delegate?.typeRef ?: return)
|
||||
FIELD -> "fields" to ((declaration as? FirBackingField)?.returnTypeRef ?: return)
|
||||
PROPERTY_DELEGATE_FIELD -> "delegate fields" to ((declaration as? FirBackingField)?.propertySymbol?.delegate?.typeRef ?: return)
|
||||
RECEIVER -> "receivers" to ((declaration as? FirCallableDeclaration)?.receiverParameter?.typeRef ?: return)
|
||||
FILE, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CONSTRUCTOR_PARAMETER, SETTER_PARAMETER, null -> when {
|
||||
declaration is FirProperty && !declaration.isLocal -> {
|
||||
@@ -216,12 +217,15 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
|
||||
)
|
||||
}
|
||||
FIELD -> {
|
||||
if (annotated is FirProperty && annotated.delegateFieldSymbol != null && !annotated.hasBackingField) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD, context)
|
||||
if (annotated is FirBackingField) {
|
||||
val propertySymbol = annotated.propertySymbol
|
||||
if (propertySymbol.delegateFieldSymbol != null && !propertySymbol.hasBackingField) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
PROPERTY_DELEGATE_FIELD -> {
|
||||
if (annotated is FirProperty && annotated.delegateFieldSymbol == null) {
|
||||
if (annotated is FirBackingField && annotated.propertySymbol.delegateFieldSymbol == null) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, context)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -24,8 +24,7 @@ object FirVolatileAnnotationChecker : FirPropertyChecker() {
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.source?.kind != KtRealSourceElementKind) return
|
||||
|
||||
val fieldAnnotation = declaration.annotations.getAnnotationByClassIds(VOLATILE_CLASS_IDS, context.session)
|
||||
?: declaration.backingField?.annotations?.getAnnotationByClassIds(VOLATILE_CLASS_IDS, context.session)
|
||||
val fieldAnnotation = declaration.backingField?.annotations?.getAnnotationByClassIds(VOLATILE_CLASS_IDS, context.session)
|
||||
?: return
|
||||
|
||||
if (!declaration.isVar) {
|
||||
|
||||
+10
-54
@@ -5,28 +5,25 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.backend.generators
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
|
||||
import org.jetbrains.kotlin.fir.declarations.FirBackingField
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.useSiteTargetsFromMetaAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.util.isSetter
|
||||
|
||||
/**
|
||||
* A generator that converts annotations in [FirAnnotationContainer] to annotations in [IrMutableAnnotationContainer].
|
||||
*
|
||||
* In general, annotations are bound to the target in the beginning, i.e., clearly targeted at source level. But, there are some cases that
|
||||
* need special handling: [AnnotationUseSiteTarget]. In particular, [FirProperty] contains all annotations associated with that property,
|
||||
* whose targets may vary. After all the necessary pieces of IR elements, e.g., backing field, are ready, this generator splits those
|
||||
* annotations to the specified targets.
|
||||
* Annotations are bound to the target already in frontend, e.g.
|
||||
*
|
||||
* Note: Annotations on primary constructor properties are already split between value parameters and properties in FIR. Before this change,
|
||||
* it used to be done here.
|
||||
* + Annotations on primary constructor properties are already split between value parameters, properties and backing fields in FIR.</li>
|
||||
* + Annotations on regular properties are also already split between properties and backing fields.</li>
|
||||
*
|
||||
* So this class task is only to convert FirAnnotations to IrAnnotations.
|
||||
* Some time before, it performed also annotation splitting between use-site targets.
|
||||
*/
|
||||
class AnnotationGenerator(private val components: Fir2IrComponents) : Fir2IrComponents by components {
|
||||
|
||||
@@ -39,56 +36,15 @@ class AnnotationGenerator(private val components: Fir2IrComponents) : Fir2IrComp
|
||||
irContainer.annotations = firContainer.annotations.toIrAnnotations()
|
||||
}
|
||||
|
||||
private fun FirAnnotation.target(applicable: List<AnnotationUseSiteTarget>): AnnotationUseSiteTarget? =
|
||||
useSiteTarget ?: applicable.firstOrNull(useSiteTargetsFromMetaAnnotation(session)::contains)
|
||||
|
||||
companion object {
|
||||
private val propertyTargets = listOf(AnnotationUseSiteTarget.PROPERTY, AnnotationUseSiteTarget.FIELD)
|
||||
private val delegatedPropertyTargets = propertyTargets + listOf(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD)
|
||||
}
|
||||
|
||||
fun generate(irValueParameter: IrValueParameter, firValueParameter: FirValueParameter) {
|
||||
irValueParameter.annotations += firValueParameter.annotations.toIrAnnotations()
|
||||
}
|
||||
|
||||
fun generate(irProperty: IrProperty, property: FirProperty) {
|
||||
val applicableTargets = if (irProperty.isDelegated) delegatedPropertyTargets else propertyTargets
|
||||
irProperty.annotations += property.annotations
|
||||
.filter { it.target(applicableTargets) == AnnotationUseSiteTarget.PROPERTY }
|
||||
.toIrAnnotations()
|
||||
irProperty.annotations += property.annotations.toIrAnnotations()
|
||||
}
|
||||
|
||||
fun generate(irField: IrField, property: FirProperty) {
|
||||
val irProperty = irField.correspondingPropertySymbol?.owner ?: throw AssertionError("$irField is not a property field")
|
||||
|
||||
val applicableTargets = if (irProperty.isDelegated) delegatedPropertyTargets else propertyTargets
|
||||
property.backingField?.let {
|
||||
irField.annotations += it.annotations.filter {
|
||||
val target = it.target(applicableTargets)
|
||||
target == AnnotationUseSiteTarget.FIELD || target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
|
||||
}.toIrAnnotations()
|
||||
}
|
||||
}
|
||||
|
||||
fun generate(propertyAccessor: IrFunction, property: FirProperty) {
|
||||
assert(propertyAccessor.isPropertyAccessor) { "$propertyAccessor is not a property accessor." }
|
||||
if (propertyAccessor.isSetter) {
|
||||
propertyAccessor.annotations += property.annotations
|
||||
.filter { it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_SETTER }
|
||||
.toIrAnnotations()
|
||||
val parameter = propertyAccessor.valueParameters.last()
|
||||
parameter.annotations += property.annotations
|
||||
.filter { it.useSiteTarget == AnnotationUseSiteTarget.SETTER_PARAMETER }
|
||||
.toIrAnnotations()
|
||||
} else {
|
||||
propertyAccessor.annotations += property.annotations
|
||||
.filter { it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_GETTER }
|
||||
.toIrAnnotations()
|
||||
}
|
||||
propertyAccessor.extensionReceiverParameter?.let { receiver ->
|
||||
receiver.annotations += property.annotations
|
||||
.filter { it.useSiteTarget == AnnotationUseSiteTarget.RECEIVER }
|
||||
.toIrAnnotations()
|
||||
}
|
||||
fun generate(irField: IrField, backingField: FirBackingField) {
|
||||
irField.annotations += backingField.annotations.toIrAnnotations()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -267,7 +267,7 @@ internal class ClassMemberGenerator(
|
||||
}
|
||||
declarationStorage.leaveScope(this@initializeBackingField)
|
||||
}
|
||||
annotationGenerator.generate(irField, property)
|
||||
property.backingField?.let { annotationGenerator.generate(irField, it) }
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.setPropertyAccessorContent(
|
||||
@@ -314,7 +314,6 @@ internal class ClassMemberGenerator(
|
||||
}
|
||||
|
||||
}
|
||||
annotationGenerator.generate(this, property)
|
||||
}
|
||||
|
||||
private fun IrFieldAccessExpression.setReceiver(declaration: IrDeclaration): IrFieldAccessExpression {
|
||||
|
||||
-7
@@ -318,13 +318,6 @@ class DelegatedMemberGenerator(private val components: Fir2IrComponents) : Fir2I
|
||||
basePropertySymbols[delegateProperty] = baseSymbols
|
||||
annotationGenerator.generate(delegateProperty, firDelegateProperty)
|
||||
|
||||
val getter = delegateProperty.getter!!
|
||||
annotationGenerator.generate(getter, firDelegateProperty)
|
||||
if (delegateProperty.isVar) {
|
||||
val setter = delegateProperty.setter!!
|
||||
annotationGenerator.generate(setter, firDelegateProperty)
|
||||
}
|
||||
|
||||
return delegateProperty
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,9 @@ class Fir2IrLazyProperty(
|
||||
}
|
||||
}?.apply {
|
||||
this.parent = this@Fir2IrLazyProperty.parent
|
||||
this.annotations = fir.backingField?.annotations?.mapNotNull {
|
||||
callGenerator.convertToIrConstructorCall(it) as? IrConstructorCall
|
||||
}.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -70,7 +70,8 @@ fun FirAnnotationContainer.nonSourceAnnotations(session: FirSession): List<FirAn
|
||||
annotations.nonSourceAnnotations(session)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun FirProperty.hasJvmFieldAnnotation(session: FirSession): Boolean = annotations.any { it.isJvmFieldAnnotation(session) }
|
||||
inline fun FirProperty.hasJvmFieldAnnotation(session: FirSession): Boolean =
|
||||
backingField?.annotations?.any { it.isJvmFieldAnnotation(session) } == true
|
||||
|
||||
fun FirAnnotation.isJvmFieldAnnotation(session: FirSession): Boolean =
|
||||
toAnnotationClassId(session) == StandardClassIds.Annotations.JvmField
|
||||
|
||||
+10
-3
@@ -1220,7 +1220,12 @@ class DeclarationsConverter(
|
||||
|
||||
typeParameterList?.let { firTypeParameters += convertTypeParameters(it, typeConstraints, symbol) }
|
||||
|
||||
backingField = fieldDeclaration.convertBackingField(symbol, modifiers, returnType, isVar)
|
||||
backingField = fieldDeclaration.convertBackingField(
|
||||
symbol, modifiers, returnType, isVar,
|
||||
if (isLocal) emptyList() else modifiers.annotations.filter {
|
||||
it.useSiteTarget == FIELD || it.useSiteTarget == PROPERTY_DELEGATE_FIELD
|
||||
}
|
||||
)
|
||||
|
||||
if (isLocal) {
|
||||
this.isLocal = true
|
||||
@@ -1318,7 +1323,7 @@ class DeclarationsConverter(
|
||||
}
|
||||
}
|
||||
annotations += if (isLocal) modifiers.annotations else modifiers.annotations.filter {
|
||||
it.useSiteTarget != PROPERTY_GETTER &&
|
||||
it.useSiteTarget != FIELD && it.useSiteTarget != PROPERTY_DELEGATE_FIELD && it.useSiteTarget != PROPERTY_GETTER &&
|
||||
(!isVar || it.useSiteTarget != SETTER_PARAMETER && it.useSiteTarget != PROPERTY_SETTER)
|
||||
}
|
||||
|
||||
@@ -1503,6 +1508,7 @@ class DeclarationsConverter(
|
||||
propertyModifiers: Modifier,
|
||||
propertyReturnType: FirTypeRef,
|
||||
isVar: Boolean,
|
||||
annotationsFromProperty: List<FirAnnotationCall>,
|
||||
): FirBackingField {
|
||||
var modifiers = Modifier()
|
||||
var returnType: FirTypeRef = implicitType
|
||||
@@ -1532,6 +1538,7 @@ class DeclarationsConverter(
|
||||
symbol = FirBackingFieldSymbol(CallableId(name))
|
||||
this.status = status
|
||||
annotations += modifiers.annotations
|
||||
annotations += annotationsFromProperty
|
||||
this.propertySymbol = propertySymbol
|
||||
this.initializer = backingFieldInitializer
|
||||
this.isVar = isVar
|
||||
@@ -1540,7 +1547,7 @@ class DeclarationsConverter(
|
||||
} else {
|
||||
FirDefaultPropertyBackingField(
|
||||
moduleData = baseModuleData,
|
||||
annotations = mutableListOf(),
|
||||
annotations = annotationsFromProperty.toMutableList(),
|
||||
returnTypeRef = propertyReturnType.copyWithNewSourceKind(KtFakeSourceElementKind.DefaultAccessor),
|
||||
isVar = isVar,
|
||||
propertySymbol = propertySymbol,
|
||||
|
||||
+5
-4
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.lightTree.fir
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
|
||||
import org.jetbrains.kotlin.fakeElement
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.builder.Context
|
||||
@@ -136,16 +137,16 @@ class ValueParameter(
|
||||
}
|
||||
backingField = FirDefaultPropertyBackingField(
|
||||
moduleData = moduleData,
|
||||
annotations = mutableListOf(),
|
||||
annotations = modifiers.annotations.filter {
|
||||
it.useSiteTarget == FIELD || it.useSiteTarget == PROPERTY_DELEGATE_FIELD
|
||||
}.toMutableList(),
|
||||
returnTypeRef = returnTypeRef.copyWithNewSourceKind(KtFakeSourceElementKind.DefaultAccessor),
|
||||
isVar = isVar,
|
||||
propertySymbol = symbol,
|
||||
status = status.copy(),
|
||||
)
|
||||
annotations += modifiers.annotations.filter {
|
||||
it.useSiteTarget == null || it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY ||
|
||||
it.useSiteTarget == AnnotationUseSiteTarget.FIELD ||
|
||||
it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
|
||||
it.useSiteTarget == null || it.useSiteTarget == PROPERTY
|
||||
}
|
||||
val defaultAccessorSource = propertySource?.fakeElement(KtFakeSourceElementKind.DefaultAccessor)
|
||||
getter = FirDefaultPropertyGetter(
|
||||
|
||||
+10
@@ -46,6 +46,16 @@ public class LightTree2FirConverterTestCaseGenerated extends AbstractLightTree2F
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationOnField.kt")
|
||||
public void testAnnotationOnField() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnField.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationOnProperty.kt")
|
||||
public void testAnnotationOnProperty() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
|
||||
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnNullableParenthesizedTypes.kt");
|
||||
|
||||
@@ -540,6 +540,7 @@ open class RawFirBuilder(
|
||||
property: KtProperty,
|
||||
propertySymbol: FirPropertySymbol,
|
||||
propertyReturnType: FirTypeRef,
|
||||
annotationsFromProperty: List<FirAnnotationCall>,
|
||||
): FirBackingField {
|
||||
val componentVisibility = if (this?.visibility != null && this.visibility != Visibilities.Unknown) {
|
||||
this.visibility
|
||||
@@ -558,6 +559,7 @@ open class RawFirBuilder(
|
||||
returnTypeRef = returnType
|
||||
this.status = status
|
||||
extractAnnotationsTo(this)
|
||||
this.annotations += annotationsFromProperty
|
||||
name = BACKING_FIELD
|
||||
symbol = FirBackingFieldSymbol(CallableId(name))
|
||||
this.propertySymbol = propertySymbol
|
||||
@@ -570,7 +572,7 @@ open class RawFirBuilder(
|
||||
} else {
|
||||
FirDefaultPropertyBackingField(
|
||||
moduleData = baseModuleData,
|
||||
annotations = mutableListOf(),
|
||||
annotations = annotationsFromProperty.toMutableList(),
|
||||
returnTypeRef = propertyReturnType.copyWithNewSourceKind(KtFakeSourceElementKind.DefaultAccessor),
|
||||
isVar = property.isVar,
|
||||
propertySymbol = propertySymbol,
|
||||
@@ -654,7 +656,9 @@ open class RawFirBuilder(
|
||||
isLocal = false
|
||||
backingField = FirDefaultPropertyBackingField(
|
||||
moduleData = baseModuleData,
|
||||
annotations = mutableListOf(),
|
||||
annotations = parameterAnnotations.filter {
|
||||
it.useSiteTarget == FIELD || it.useSiteTarget == PROPERTY_DELEGATE_FIELD
|
||||
}.toMutableList(),
|
||||
returnTypeRef = returnTypeRef.copyWithNewSourceKind(KtFakeSourceElementKind.DefaultAccessor),
|
||||
isVar = isVar,
|
||||
propertySymbol = symbol,
|
||||
@@ -687,9 +691,7 @@ open class RawFirBuilder(
|
||||
setter.replaceAnnotations(parameterAnnotations.filterUseSiteTarget(PROPERTY_SETTER))
|
||||
} else null
|
||||
annotations += parameterAnnotations.filter {
|
||||
it.useSiteTarget == null || it.useSiteTarget == PROPERTY ||
|
||||
it.useSiteTarget == FIELD ||
|
||||
it.useSiteTarget == PROPERTY_DELEGATE_FIELD
|
||||
it.useSiteTarget == null || it.useSiteTarget == PROPERTY
|
||||
}
|
||||
|
||||
dispatchReceiverType = currentDispatchReceiverType()
|
||||
@@ -1767,6 +1769,7 @@ open class RawFirBuilder(
|
||||
this@toFirProperty,
|
||||
propertySymbol = symbol,
|
||||
propertyType,
|
||||
emptyList(),
|
||||
)
|
||||
|
||||
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL).apply {
|
||||
@@ -1801,6 +1804,7 @@ open class RawFirBuilder(
|
||||
this@toFirProperty,
|
||||
propertySymbol = symbol,
|
||||
propertyType,
|
||||
propertyAnnotations.filter { it.useSiteTarget == FIELD || it.useSiteTarget == PROPERTY_DELEGATE_FIELD },
|
||||
)
|
||||
|
||||
getter = this@toFirProperty.getter.toFirPropertyAccessor(
|
||||
@@ -1856,7 +1860,7 @@ open class RawFirBuilder(
|
||||
}
|
||||
}
|
||||
annotations += if (isLocal) propertyAnnotations else propertyAnnotations.filter {
|
||||
it.useSiteTarget != PROPERTY_GETTER &&
|
||||
it.useSiteTarget != FIELD && it.useSiteTarget != PROPERTY_DELEGATE_FIELD && it.useSiteTarget != PROPERTY_GETTER &&
|
||||
(!isVar || it.useSiteTarget != SETTER_PARAMETER && it.useSiteTarget != PROPERTY_SETTER)
|
||||
}
|
||||
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
annotation class Ann
|
||||
|
||||
class CustomDelegate {
|
||||
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String = prop.name
|
||||
}
|
||||
|
||||
@field:Ann
|
||||
class SomeClass {
|
||||
|
||||
@field:Ann
|
||||
constructor()
|
||||
|
||||
@field:Ann
|
||||
protected val simpleProperty: String = "text"
|
||||
|
||||
@field:[Ann]
|
||||
protected val simplePropertyWithAnnotationList: String = "text"
|
||||
|
||||
@field:Ann
|
||||
protected val delegatedProperty: String by CustomDelegate()
|
||||
|
||||
@field:Ann
|
||||
val propertyWithCustomGetter: Int
|
||||
get() = 5
|
||||
|
||||
@field:Ann
|
||||
fun anotherFun(@field:Ann s: String) {
|
||||
@field:Ann
|
||||
val localVariable = 5
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WithPrimaryConstructor(@field:Ann val a: String)
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
FILE: annotationOnField.kt
|
||||
public? final? annotation class Ann : R|kotlin/Annotation| {
|
||||
public? constructor(): R|Ann| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
}
|
||||
public? final? class CustomDelegate : R|kotlin/Any| {
|
||||
public? constructor(): R|CustomDelegate| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
public? final? operator fun getValue(thisRef: Any?, prop: KProperty<*>): String { LAZY_BLOCK }
|
||||
|
||||
}
|
||||
@FIELD:Ann() public? final? class SomeClass : R|kotlin/Any| {
|
||||
@FIELD:Ann() public? constructor(): R|SomeClass| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() protected final? val simpleProperty: String = LAZY_EXPRESSION
|
||||
protected get(): String
|
||||
|
||||
field:@FIELD:Ann() protected final? val simplePropertyWithAnnotationList: String = LAZY_EXPRESSION
|
||||
protected get(): String
|
||||
|
||||
field:@FIELD:Ann() protected final? val delegatedProperty: Stringby LAZY_EXPRESSION
|
||||
protected get(): <implicit> {
|
||||
^ this@R|/SomeClass|.D|/SomeClass.delegatedProperty|.getValue#(this@R|/SomeClass|, ::R|/SomeClass.delegatedProperty|)
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() public? final? val propertyWithCustomGetter: Int
|
||||
public? get(): Int { LAZY_BLOCK }
|
||||
|
||||
@FIELD:Ann() public? final? fun anotherFun(@FIELD:Ann() s: String): R|kotlin/Unit| { LAZY_BLOCK }
|
||||
|
||||
}
|
||||
public? final? class WithPrimaryConstructor : R|kotlin/Any| {
|
||||
public? constructor(a: String): R|WithPrimaryConstructor| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() public? final? val a: String = R|<local>/a|
|
||||
public? get(): String
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
FILE: annotationOnField.kt
|
||||
public? final? annotation class Ann : R|kotlin/Annotation| {
|
||||
public? [ContainingClassKey=Ann] constructor(): R|Ann| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public? final? class CustomDelegate : R|kotlin/Any| {
|
||||
public? [ContainingClassKey=CustomDelegate] constructor(): R|CustomDelegate| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public? final? operator fun getValue(thisRef: Any?, prop: KProperty<*>): String {
|
||||
^getValue prop#.name#
|
||||
}
|
||||
|
||||
}
|
||||
@FIELD:Ann() public? final? class SomeClass : R|kotlin/Any| {
|
||||
@FIELD:Ann() public? [ContainingClassKey=SomeClass] constructor(): R|SomeClass| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() protected final? val simpleProperty: String = String(text)
|
||||
protected [ContainingClassKey=SomeClass] get(): String
|
||||
|
||||
field:@FIELD:Ann() protected final? val simplePropertyWithAnnotationList: String = String(text)
|
||||
protected [ContainingClassKey=SomeClass] get(): String
|
||||
|
||||
field:@FIELD:Ann() protected final? val delegatedProperty: Stringby CustomDelegate#()
|
||||
protected [ContainingClassKey=SomeClass] get(): <implicit> {
|
||||
^ this@R|/SomeClass|.D|/SomeClass.delegatedProperty|.getValue#(this@R|/SomeClass|, ::R|/SomeClass.delegatedProperty|)
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() public? final? val propertyWithCustomGetter: Int
|
||||
public? [ContainingClassKey=SomeClass] get(): Int {
|
||||
^ IntegerLiteral(5)
|
||||
}
|
||||
|
||||
@FIELD:Ann() public? final? fun anotherFun(@FIELD:Ann() s: String): R|kotlin/Unit| {
|
||||
@FIELD:Ann() lval localVariable: <implicit> = IntegerLiteral(5)
|
||||
}
|
||||
|
||||
}
|
||||
public? final? class WithPrimaryConstructor : R|kotlin/Any| {
|
||||
public? [ContainingClassKey=WithPrimaryConstructor] constructor([CorrespondingProperty=/WithPrimaryConstructor.a] a: String): R|WithPrimaryConstructor| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() public? final? [IsFromPrimaryConstructor=true] val a: String = R|<local>/a|
|
||||
public? [ContainingClassKey=WithPrimaryConstructor] get(): String
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
annotation class Ann
|
||||
|
||||
@field:Ann
|
||||
val x: Int = 1
|
||||
|
||||
@property:Ann
|
||||
val y: Int = 2
|
||||
|
||||
@Ann
|
||||
val z: Int = 3
|
||||
|
||||
class Some(@field:Ann val x: Int, @property: Ann val y: Int, @param:Ann val z: Int, val w: Int) {
|
||||
@field:Ann
|
||||
val a: Int = 1
|
||||
|
||||
@property:Ann
|
||||
val b: Int = 2
|
||||
|
||||
@Ann
|
||||
val c: Int = 3
|
||||
}
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
FILE: annotationOnProperty.kt
|
||||
public? final? annotation class Ann : R|kotlin/Annotation| {
|
||||
public? constructor(): R|Ann| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
}
|
||||
field:@FIELD:Ann() public? final? val x: Int = LAZY_EXPRESSION
|
||||
public? get(): Int
|
||||
@PROPERTY:Ann() public? final? val y: Int = LAZY_EXPRESSION
|
||||
public? get(): Int
|
||||
@Ann() public? final? val z: Int = LAZY_EXPRESSION
|
||||
public? get(): Int
|
||||
public? final? class Some : R|kotlin/Any| {
|
||||
public? constructor(x: Int, y: Int, @CONSTRUCTOR_PARAMETER:Ann() z: Int, w: Int): R|Some| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() public? final? val x: Int = R|<local>/x|
|
||||
public? get(): Int
|
||||
|
||||
@PROPERTY:Ann() public? final? val y: Int = R|<local>/y|
|
||||
public? get(): Int
|
||||
|
||||
public? final? val z: Int = R|<local>/z|
|
||||
public? get(): Int
|
||||
|
||||
public? final? val w: Int = R|<local>/w|
|
||||
public? get(): Int
|
||||
|
||||
field:@FIELD:Ann() public? final? val a: Int = LAZY_EXPRESSION
|
||||
public? get(): Int
|
||||
|
||||
@PROPERTY:Ann() public? final? val b: Int = LAZY_EXPRESSION
|
||||
public? get(): Int
|
||||
|
||||
@Ann() public? final? val c: Int = LAZY_EXPRESSION
|
||||
public? get(): Int
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
FILE: annotationOnProperty.kt
|
||||
public? final? annotation class Ann : R|kotlin/Annotation| {
|
||||
public? [ContainingClassKey=Ann] constructor(): R|Ann| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
field:@FIELD:Ann() public? final? val x: Int = IntegerLiteral(1)
|
||||
public? get(): Int
|
||||
@PROPERTY:Ann() public? final? val y: Int = IntegerLiteral(2)
|
||||
public? get(): Int
|
||||
@Ann() public? final? val z: Int = IntegerLiteral(3)
|
||||
public? get(): Int
|
||||
public? final? class Some : R|kotlin/Any| {
|
||||
public? [ContainingClassKey=Some] constructor([CorrespondingProperty=/Some.x] x: Int, [CorrespondingProperty=/Some.y] y: Int, [CorrespondingProperty=/Some.z] @CONSTRUCTOR_PARAMETER:Ann() z: Int, [CorrespondingProperty=/Some.w] w: Int): R|Some| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
field:@FIELD:Ann() public? final? [IsFromPrimaryConstructor=true] val x: Int = R|<local>/x|
|
||||
public? [ContainingClassKey=Some] get(): Int
|
||||
|
||||
@PROPERTY:Ann() public? final? [IsFromPrimaryConstructor=true] val y: Int = R|<local>/y|
|
||||
public? [ContainingClassKey=Some] get(): Int
|
||||
|
||||
public? final? [IsFromPrimaryConstructor=true] val z: Int = R|<local>/z|
|
||||
public? [ContainingClassKey=Some] get(): Int
|
||||
|
||||
public? final? [IsFromPrimaryConstructor=true] val w: Int = R|<local>/w|
|
||||
public? [ContainingClassKey=Some] get(): Int
|
||||
|
||||
field:@FIELD:Ann() public? final? val a: Int = IntegerLiteral(1)
|
||||
public? [ContainingClassKey=Some] get(): Int
|
||||
|
||||
@PROPERTY:Ann() public? final? val b: Int = IntegerLiteral(2)
|
||||
public? [ContainingClassKey=Some] get(): Int
|
||||
|
||||
@Ann() public? final? val c: Int = IntegerLiteral(3)
|
||||
public? [ContainingClassKey=Some] get(): Int
|
||||
|
||||
}
|
||||
+10
@@ -46,6 +46,16 @@ public class RawFirBuilderLazyBodiesTestCaseGenerated extends AbstractRawFirBuil
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationOnField.kt")
|
||||
public void testAnnotationOnField() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnField.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationOnProperty.kt")
|
||||
public void testAnnotationOnProperty() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
|
||||
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnNullableParenthesizedTypes.kt");
|
||||
|
||||
+10
@@ -46,6 +46,16 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationOnField.kt")
|
||||
public void testAnnotationOnField() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnField.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationOnProperty.kt")
|
||||
public void testAnnotationOnProperty() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
|
||||
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnNullableParenthesizedTypes.kt");
|
||||
|
||||
+22
-18
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers
|
||||
import kotlinx.collections.immutable.*
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.correspondingProperty
|
||||
@@ -147,7 +148,7 @@ open class FirTypeResolveTransformer(
|
||||
if (result.isPrimary) {
|
||||
for (valueParameter in result.valueParameters) {
|
||||
if (valueParameter.correspondingProperty != null) {
|
||||
valueParameter.removeIrrelevantAnnotations()
|
||||
valueParameter.moveOrDeleteIrrelevantAnnotations()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,10 +219,7 @@ open class FirTypeResolveTransformer(
|
||||
|
||||
unboundCyclesInTypeParametersSupertypes(property)
|
||||
|
||||
if (property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) {
|
||||
property.removeIrrelevantAnnotations()
|
||||
}
|
||||
|
||||
property.moveOrDeleteIrrelevantAnnotations()
|
||||
calculateDeprecations(property)
|
||||
property
|
||||
}
|
||||
@@ -486,37 +484,43 @@ open class FirTypeResolveTransformer(
|
||||
* class Foo(@Ann val x: String)
|
||||
* ```
|
||||
* This ambiguity may be resolved by specifying the use-site explicitly, i.e. `@field:Ann` or by analysing the allowed targets from
|
||||
* the [kotlin.annotation.Target] meta-annotation. In latter case, the method will assign a use-site target to the corresponding
|
||||
* annotation.
|
||||
* the [kotlin.annotation.Target] meta-annotation.
|
||||
* In latter case, the method will ensure that the annotation is moved to the correct element (field or parameter) or left at the property.
|
||||
*/
|
||||
private fun FirVariable.removeIrrelevantAnnotations() {
|
||||
private fun FirVariable.moveOrDeleteIrrelevantAnnotations() {
|
||||
if (annotations.isEmpty()) return
|
||||
val backingFieldAnnotations by lazy(LazyThreadSafetyMode.NONE) { backingField?.annotations?.toMutableList() ?: mutableListOf() }
|
||||
var replaceBackingFieldAnnotations = false
|
||||
replaceAnnotations(annotations.filter { annotation ->
|
||||
when(annotation.useSiteTarget) {
|
||||
when (annotation.useSiteTarget) {
|
||||
null -> {
|
||||
val allowedTargets = annotation.useSiteTargetsFromMetaAnnotation(session)
|
||||
when {
|
||||
this is FirValueParameter -> AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER in allowedTargets
|
||||
this.source?.kind == KtFakeSourceElementKind.PropertyFromParameter && AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER in allowedTargets -> false
|
||||
this is FirProperty && AnnotationUseSiteTarget.FIELD in allowedTargets && AnnotationUseSiteTarget.PROPERTY !in allowedTargets && backingField != null -> {
|
||||
(this as? FirProperty)?.backingField?.replaceAnnotations(backingField!!.annotations + annotation)
|
||||
this is FirValueParameter -> CONSTRUCTOR_PARAMETER in allowedTargets
|
||||
this.source?.kind == KtFakeSourceElementKind.PropertyFromParameter && CONSTRUCTOR_PARAMETER in allowedTargets -> false
|
||||
this is FirProperty && backingField != null && annotationShouldBeMovedToField(allowedTargets) -> {
|
||||
backingFieldAnnotations += annotation
|
||||
replaceBackingFieldAnnotations = true
|
||||
false
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> this is FirValueParameter
|
||||
AnnotationUseSiteTarget.FIELD -> {
|
||||
(this as? FirProperty)?.backingField?.replaceAnnotations(backingField!!.annotations + annotation)
|
||||
false
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
})
|
||||
if (replaceBackingFieldAnnotations) {
|
||||
backingField?.replaceAnnotations(backingFieldAnnotations)
|
||||
}
|
||||
}
|
||||
|
||||
private fun annotationShouldBeMovedToField(allowedTargets: Set<AnnotationUseSiteTarget>): Boolean =
|
||||
(FIELD in allowedTargets || PROPERTY_DELEGATE_FIELD in allowedTargets) && PROPERTY !in allowedTargets
|
||||
|
||||
private fun calculateDeprecations(callableDeclaration: FirCallableDeclaration) {
|
||||
if (callableDeclaration.deprecationsProvider is UnresolvedDeprecationProvider) {
|
||||
callableDeclaration.replaceDeprecationsProvider(callableDeclaration.getDeprecationsProvider(session))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -128,7 +128,7 @@ open class FirDeclarationsResolveTransformer(
|
||||
val bodyResolveState = property.bodyResolveState
|
||||
if (bodyResolveState == FirPropertyBodyResolveState.EVERYTHING_RESOLVED) return property
|
||||
|
||||
val canHaveDeepImplicitTypeRefs = property.hasExplicitBackingField
|
||||
val canHaveDeepImplicitTypeRefs = property.backingField != null
|
||||
if (returnTypeRefBeforeResolve !is FirImplicitTypeRef && implicitTypeOnly && !canHaveDeepImplicitTypeRefs) {
|
||||
return property
|
||||
}
|
||||
@@ -930,6 +930,7 @@ open class FirDeclarationsResolveTransformer(
|
||||
else -> ResolutionMode.ContextDependent
|
||||
}
|
||||
backingField.transformInitializer(transformer, initializerData)
|
||||
backingField.transformAnnotations(transformer, data)
|
||||
if (
|
||||
backingField.returnTypeRef is FirErrorTypeRef ||
|
||||
backingField.returnTypeRef is FirResolvedTypeRef
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ open class FirImplicitAwareBodyResolveTransformer(
|
||||
return transform()
|
||||
}
|
||||
|
||||
val canHaveDeepImplicitTypeRefs = member is FirProperty && member.hasExplicitBackingField
|
||||
val canHaveDeepImplicitTypeRefs = member is FirProperty && member.backingField != null
|
||||
|
||||
if (member.returnTypeRef is FirResolvedTypeRef && !canHaveDeepImplicitTypeRefs) return member
|
||||
val symbol = member.symbol
|
||||
|
||||
+6
@@ -171,6 +171,7 @@ private class FirDeclarationsResolveTransformerForAnnotationArgumentsMapping(
|
||||
.transformReturnTypeRef(transformer, data)
|
||||
.transformGetter(transformer, data)
|
||||
.transformSetter(transformer, data)
|
||||
.transformBackingField(transformer, data)
|
||||
}
|
||||
|
||||
return property
|
||||
@@ -212,6 +213,11 @@ private class FirDeclarationsResolveTransformerForAnnotationArgumentsMapping(
|
||||
return field
|
||||
}
|
||||
|
||||
override fun transformBackingField(backingField: FirBackingField, data: ResolutionMode): FirStatement {
|
||||
backingField.transformAnnotations(transformer, data)
|
||||
return backingField
|
||||
}
|
||||
|
||||
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: ResolutionMode): FirTypeAlias {
|
||||
doTransformTypeParameters(typeAlias)
|
||||
typeAlias.transformAnnotations(transformer, data)
|
||||
|
||||
@@ -199,6 +199,13 @@ class FirRenderer(
|
||||
override fun visitCallableDeclaration(callableDeclaration: FirCallableDeclaration) {
|
||||
renderContexts(callableDeclaration.contextReceivers)
|
||||
annotationRenderer?.render(callableDeclaration)
|
||||
if (callableDeclaration is FirProperty) {
|
||||
val backingField = callableDeclaration.backingField
|
||||
if (backingField?.annotations?.isNotEmpty() == true) {
|
||||
print("field:")
|
||||
annotationRenderer?.render(backingField)
|
||||
}
|
||||
}
|
||||
visitMemberDeclaration(callableDeclaration)
|
||||
val receiverParameter = callableDeclaration.receiverParameter
|
||||
if (callableDeclaration !is FirProperty || callableDeclaration.isCatchParameter != true) {
|
||||
|
||||
@@ -38,6 +38,12 @@ open class FirPropertySymbol(
|
||||
val delegateFieldSymbol: FirDelegateFieldSymbol?
|
||||
get() = fir.delegateFieldSymbol
|
||||
|
||||
val delegate: FirExpression?
|
||||
get() = fir.delegate
|
||||
|
||||
val hasDelegate: Boolean
|
||||
get() = fir.delegate != null
|
||||
|
||||
val hasInitializer: Boolean
|
||||
get() = fir.initializer != null
|
||||
|
||||
@@ -47,9 +53,6 @@ open class FirPropertySymbol(
|
||||
return fir.initializer
|
||||
}
|
||||
|
||||
val hasDelegate: Boolean
|
||||
get() = fir.delegate != null
|
||||
|
||||
val controlFlowGraphReference: FirControlFlowGraphReference?
|
||||
get() {
|
||||
lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ FILE: test.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
@R|FieldOnly|() public final var param: R|kotlin/Int| = R|<local>/param|
|
||||
field:@R|FieldOnly|() public final var param: R|kotlin/Int| = R|<local>/param|
|
||||
public get(): R|kotlin/Int|
|
||||
public set(value: R|kotlin/Int|): R|kotlin/Unit|
|
||||
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ FILE: targetOnPrimaryCtorParameter.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
@R|PropertyOnly|() @R|PropertyOnly2|() @R|FieldOnly|() public final var param: R|kotlin/Int| = R|<local>/param|
|
||||
@R|PropertyOnly|() @R|PropertyOnly2|() field:@R|FieldOnly|() public final var param: R|kotlin/Int| = R|<local>/param|
|
||||
public get(): R|kotlin/Int|
|
||||
public set(value: R|kotlin/Int|): R|kotlin/Unit|
|
||||
|
||||
|
||||
+12
@@ -39,6 +39,18 @@ public class FirVisualizerForRawFirDataGenerated extends AbstractFirVisualizerTe
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnField.kt")
|
||||
public void testAnnotationOnField() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnProperty.kt")
|
||||
public void testAnnotationOnProperty() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnProperty.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
|
||||
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
|
||||
|
||||
+12
@@ -39,6 +39,18 @@ public class PsiVisualizerForRawFirDataGenerated extends AbstractPsiVisualizerTe
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnField.kt")
|
||||
public void testAnnotationOnField() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationOnProperty.kt")
|
||||
public void testAnnotationOnProperty() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationOnProperty.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
|
||||
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
|
||||
|
||||
+2
-1
@@ -231,7 +231,8 @@ object FirSerializationPluginClassChecker : FirClassChecker() {
|
||||
if (classSymbol.resolvedSuperTypes.any { it.classId == JAVA_SERIALIZABLE_ID }) return // do not check
|
||||
for (property in properties) {
|
||||
if (property.transient) continue
|
||||
val incorrectTransient = property.propertySymbol.annotations.getAnnotationByClassId(TRANSIENT_ANNOTATION_CLASS_ID, session)
|
||||
val incorrectTransient =
|
||||
property.propertySymbol.backingFieldSymbol?.annotations?.getAnnotationByClassId(TRANSIENT_ANNOTATION_CLASS_ID, session)
|
||||
if (incorrectTransient != null) {
|
||||
reporter.reportOn(
|
||||
source = incorrectTransient.source ?: property.propertySymbol.source,
|
||||
|
||||
Reference in New Issue
Block a user