diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index e3870ef17f3..c0562191376 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -2762,9 +2762,10 @@ open class KotlinFileExtractor( // getPsiBasedAccessorLocation): the keyword token for a bare `get`/`set`, // or the property signature for a fully synthesised accessor. fun accessorOverride(f: IrFunction) = - if (f.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) - getPsiBasedAccessorLocation(p, f)?.let { OverriddenFunctionAttributes(sourceLoc = it) } - else null + (if (f.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) + getPsiBasedAccessorLocation(p, f) + else getPsiBasedAnnotatedAccessorLocation(p, f)) + ?.let { OverriddenFunctionAttributes(sourceLoc = it) } if (getter == null) { if (!isExternalDeclaration(p)) { @@ -3132,9 +3133,37 @@ open class KotlinFileExtractor( return tw.getLocation(ktClass.startOffset, ktClass.endOffset) } + /** + * Returns the PSI-based location for an *explicit* property accessor that carries + * its own annotation(s) (for example `@JvmName("getX_prop") get() = 15`), spanning + * from the leading annotation through the end of the accessor. + * + * The K2 frontend records such an accessor with raw IR offsets that already include + * the leading annotation; the K1 frontend's raw offsets start at the `get`/`set` + * keyword and omit the annotation. We converge K1 onto the annotation-inclusive K2 + * span by recovering it from the [KtPropertyAccessor] PSI node, whose text range + * begins at its modifier list (the annotations). + * + * Returns null under K2 (where [getKtFile] is unavailable and the raw offsets + * already carry the annotation) and for accessors that declare no annotations of + * their own (which both frontends already record identically). + */ + private fun getPsiBasedAnnotatedAccessorLocation(p: IrProperty, accessor: IrFunction): Label? { + if (p.startOffset < 0 || p.endOffset < 0) return null + val file = currentIrFile ?: return null + val ktFile = getPsi2Ir()?.getKtFile(file) ?: return null + val ktProperty = ktFile.findElementAt(p.startOffset) + ?.let { leaf -> generateSequence(leaf) { it.parent }.filterIsInstance().firstOrNull() } + ?: return null + val isGetter = p.getter?.symbol == accessor.symbol + val ktAccessor: KtPropertyAccessor = (if (isGetter) ktProperty.getter else ktProperty.setter) + ?: return null + if (ktAccessor.annotationEntries.isEmpty()) return null + return tw.getLocation(ktAccessor.startOffset, ktAccessor.endOffset) + } + /** * Returns the PSI-based location for the synthesised getter/setter of a - * *delegated* property (origin `DELEGATED_PROPERTY_ACCESSOR`), spanning the * enclosing property declaration from its `val`/`var` keyword through the end of * the delegate expression. * diff --git a/java/ql/test-kotlin1/library-tests/annotations/jvmName/test.expected b/java/ql/test-kotlin1/library-tests/annotations/jvmName/test.expected index b26dff9d334..ba6887606f2 100644 --- a/java/ql/test-kotlin1/library-tests/annotations/jvmName/test.expected +++ b/java/ql/test-kotlin1/library-tests/annotations/jvmName/test.expected @@ -1,5 +1,5 @@ | Test.java:2:17:2:17 | m | m | m | -| test.kt:4:9:4:18 | getX_prop | getX_prop | getX | +| test.kt:3:9:4:18 | getX_prop | getX_prop | getX | | test.kt:6:5:6:19 | getX | getX | getX | | test.kt:10:5:10:14 | changeY | changeY | setY | | test.kt:10:5:10:14 | y | y | getY | diff --git a/java/ql/test-kotlin1/library-tests/jvmstatic-annotation/test.expected b/java/ql/test-kotlin1/library-tests/jvmstatic-annotation/test.expected index b286f4766bd..1071f7a6e03 100644 --- a/java/ql/test-kotlin1/library-tests/jvmstatic-annotation/test.expected +++ b/java/ql/test-kotlin1/library-tests/jvmstatic-annotation/test.expected @@ -12,8 +12,8 @@ staticMembers | test.kt:31:1:47:1 | NonCompanion | test.kt:33:14:33:69 | staticMethod | Method | | test.kt:31:1:47:1 | NonCompanion | test.kt:36:14:36:35 | getStaticProp | Method | | test.kt:31:1:47:1 | NonCompanion | test.kt:36:14:36:35 | setStaticProp | Method | -| test.kt:31:1:47:1 | NonCompanion | test.kt:40:16:40:43 | getPropWithStaticGetter | Method | -| test.kt:31:1:47:1 | NonCompanion | test.kt:45:16:45:58 | setPropWithStaticSetter | Method | +| test.kt:31:1:47:1 | NonCompanion | test.kt:40:5:40:43 | getPropWithStaticGetter | Method | +| test.kt:31:1:47:1 | NonCompanion | test.kt:45:5:45:58 | setPropWithStaticSetter | Method | #select | test.kt:9:1:29:1 | HasCompanion | JavaUser.java:5:5:5:34 | staticMethod(...) | JavaUser.java:5:5:5:16 | HasCompanion | static | | test.kt:9:1:29:1 | HasCompanion | JavaUser.java:7:5:7:73 | setStaticProp(...) | JavaUser.java:7:5:7:16 | HasCompanion | static |