Skip to content

Fix validity check of annotations on properties#2368

Merged
ting-yuan merged 1 commit into
google:mainfrom
ting-yuan:anno-param-prop
Mar 7, 2025
Merged

Fix validity check of annotations on properties#2368
ting-yuan merged 1 commit into
google:mainfrom
ting-yuan:anno-param-prop

Conversation

@ting-yuan

@ting-yuan ting-yuan commented Mar 7, 2025

Copy link
Copy Markdown
Contributor

Annotations on properties may come from corresponding parameters if they are declared in constructors. They may not be valid on properties and need to be filtered out. The previous implementation incorrectly excludes all annotations with @target(AnnotationTarget.VALUE_PARAMETER), while what should be excluded are the ones with @target and without @target(AnnotationTarget.PROPERTY).

@ting-yuan ting-yuan requested review from dx404 and jsjeon March 7, 2025 18:32
Annotations on properties may come from corresponding parameters if they
are declared in constructors. They may not be valid on properties and
need to be filtered out. The previous implementation incorrectly
excludes all annotations with @target(AnnotationTarget.VALUE_PARAMETER),
while what should be excluded are the ones with @target and without
@target(AnnotationTarget.PROPERTY).
@ting-yuan ting-yuan merged commit 1e8492b into google:main Mar 7, 2025

internal fun KSAnnotation.isValidOnProperty(): Boolean =
annotationType.resolve().declaration.annotations.none { metaAnnotation ->
metaAnnotation.annotationType.resolve().declaration.qualifiedName?.asString() == "kotlin.annotation.Target" &&

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: maybe it's just me, but I prefer to avoid using constant as much as possible (in case of, e.g., typo or some other silly mistakes) :)

That said, this can be Target::class.qualifiedName? Same for AnnotationTarget.PROPERTY below. (But not necessarily in this change.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix in later refactoring / polishing commits.

@@ -0,0 +1,39 @@
/*
* Copyright 2020 Google LLC
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to double-check, do these intentionally stay in 2020, or is it a good time to update the template somewhere to make this copyright comment up-to-date?

internal fun KSAnnotation.isValidOnProperty(): Boolean =
annotationType.resolve().declaration.annotations.none { metaAnnotation ->
metaAnnotation.annotationType.resolve().declaration.qualifiedName?.asString() == "kotlin.annotation.Target" &&
(metaAnnotation.arguments.singleOrNull()?.value as? ArrayList<*>)?.none {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was previously any, but now none. Is that expected?

Also, because of the inversion, now the util name sounds counter-intuitive. It is read like, if none of the annotation has non-Property target, it is valid on property?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is expected. The default behavior, i.e. without @Target on it, allows an annotation to be attached to a property. So an annotation is invalid on a property if and only if it has @Target that has no PROPERTY. This is equivalent to: an annotation is valid iff none of its meta annotations is "@Target without PROPERTY".

metaAnnotation.annotationType.resolve().declaration.qualifiedName?.asString() == "kotlin.annotation.Target" &&
(metaAnnotation.arguments.singleOrNull()?.value as? ArrayList<*>)?.none {
(it as? KSClassDeclaration)?.qualifiedName?.asString() == "kotlin.annotation.AnnotationTarget.PROPERTY"
} ?: false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the code review, it's hard to understand where this elvis operator belongs...

I wonder if the aligned indentation would help? IIUC, this is:

  (metaAnno...)?.none {
    (it as? ...)
  } ?: false

but it's currently:

  (metaAnno...)?.none {
  (it as? ...)
} ?: false

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. This is a bug of ktlint.

// FILE: com/exampel/MyClass.kt
package com.example

@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My confusion on isValidOnProperty made me wonder what happens if the annotation target doesn't have PROPERTY...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the target doesn't have PROPERTY, it is invalid and should not be included in KSPropertyDeclaration.annotations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[KSP2] Annotation missing from property when VALUE_PARAMETER target is used.

3 participants