Read KSBackingFieldJavaImpl.modifiers from the underlying Java field PSI
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSBackingFieldJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSBackingFieldJavaImpl.kt index a6cd9f4..9582b98 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSBackingFieldJavaImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSBackingFieldJavaImpl.kt
@@ -17,8 +17,10 @@ package com.google.devtools.ksp.impl.symbol.kotlin +import com.google.devtools.ksp.InternalKSPException import com.google.devtools.ksp.common.KSObjectCache import com.google.devtools.ksp.common.impl.KSNameImpl +import com.google.devtools.ksp.common.toKSModifiers import com.google.devtools.ksp.impl.symbol.kotlin.KSPropertyDeclarationJavaImpl.Companion.getCached import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl import com.google.devtools.ksp.symbol.KSBackingField @@ -29,6 +31,8 @@ import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSVisitor import com.google.devtools.ksp.symbol.KSVisitorNext +import com.google.devtools.ksp.symbol.Modifier +import com.intellij.psi.PsiModifierListOwner import org.jetbrains.kotlin.analysis.api.symbols.KaDeclarationSymbol import org.jetbrains.kotlin.analysis.api.symbols.KaJavaFieldSymbol @@ -57,6 +61,29 @@ override val ktDeclarationSymbol: KaDeclarationSymbol get() = ktJavaFieldSymbol + /** + * The modifiers of the underlying Java field. + * + * N.B.: Unlike [AbstractKSDeclarationImpl.modifiers], this deliberately does not go through + * [KaJavaFieldSymbol.toModifiers] for compiled fields. That function describes the property that KSP models on + * top of a Java field, which is always a final `val`, and therefore reports [Modifier.FINAL] for fields that are + * not final while dropping [Modifier.JAVA_TRANSIENT] and [Modifier.JAVA_VOLATILE]. A backing field is the field + * itself, so its modifiers are read from the field, which also makes them independent of whether the field was + * read from source or from a compiled artifact. + */ + override val modifiers: Set<Modifier> by lazy { + val psi = ktJavaFieldSymbol.psi + if (psi is PsiModifierListOwner) { + psi.toKSModifiers() + } else { + throw InternalKSPException( + "Expected PsiModifierListOwner for Java backing field $this", + location, + psi?.javaClass ?: javaClass + ) + } + } + override val type: KSTypeReference by lazy { KSTypeReferenceResolvedImpl.getCached(ktJavaFieldSymbol.returnType, this) }
diff --git a/kotlin-analysis-api/testData/javaBackingFields.kt b/kotlin-analysis-api/testData/javaBackingFields.kt index 5e7ffc1..f671322 100644 --- a/kotlin-analysis-api/testData/javaBackingFields.kt +++ b/kotlin-analysis-api/testData/javaBackingFields.kt
@@ -19,17 +19,17 @@ // EXPECTED: // lib.Fields // - lib.Fields.x: kotlin.Int - [PRIVATE, FINAL] -// EXPECT NEXT: - lib.Fields.x.field: kotlin.Int - [PRIVATE, FINAL] +// EXPECT NEXT: - lib.Fields.x.field: kotlin.Int - [PRIVATE] // - lib.Fields.y: kotlin.Int - [PUBLIC, FINAL] -// EXPECT NEXT: - lib.Fields.y.field: kotlin.Int - [PUBLIC, FINAL] +// EXPECT NEXT: - lib.Fields.y.field: kotlin.Int - [PUBLIC] // - lib.Fields.z: kotlin.Int - [PROTECTED, FINAL] -// EXPECT NEXT: - lib.Fields.z.field: kotlin.Int - [PROTECTED, FINAL] +// EXPECT NEXT: - lib.Fields.z.field: kotlin.Int - [PROTECTED] // - lib.Fields.w: kotlin.Int - [FINAL] -// EXPECT NEXT: - lib.Fields.w.field: kotlin.Int - [FINAL] +// EXPECT NEXT: - lib.Fields.w.field: kotlin.Int - [] // lib.AccessorsOnly // lib.ObscureFields // - lib.ObscureFields.back: kotlin.Int - [PRIVATE, FINAL] -// EXPECT NEXT: - lib.ObscureFields.back.field: kotlin.Int - [PRIVATE, FINAL] +// EXPECT NEXT: - lib.ObscureFields.back.field: kotlin.Int - [PRIVATE] // SourceFields // - SourceFields.x: kotlin.Int - [PRIVATE] // EXPECT NEXT: - SourceFields.x.field: kotlin.Int - [PRIVATE]
diff --git a/kotlin-analysis-api/testData/javaModifiers.kt b/kotlin-analysis-api/testData/javaModifiers.kt index 1953a39..85fdf6c 100644 --- a/kotlin-analysis-api/testData/javaModifiers.kt +++ b/kotlin-analysis-api/testData/javaModifiers.kt
@@ -35,22 +35,22 @@ // DependencyOuterJavaClass.DependencyInnerJavaClass: INNER OPEN PUBLIC : PUBLIC // DependencyOuterJavaClass.DependencyNestedJavaClass.<init>: FINAL PUBLIC : FINAL PUBLIC // DependencyOuterJavaClass.DependencyNestedJavaClass: OPEN PUBLIC : PUBLIC -// EXPECT NEXT: DependencyOuterJavaClass.staticPackageProtectedField.field: FINAL JAVA_STATIC : FINAL JAVA_STATIC +// EXPECT NEXT: DependencyOuterJavaClass.staticPackageProtectedField.field: JAVA_STATIC : JAVA_STATIC // DependencyOuterJavaClass.staticPackageProtectedField: FINAL JAVA_STATIC : FINAL JAVA_STATIC // DependencyOuterJavaClass.staticPackageProtectedMethod: FINAL JAVA_STATIC : FINAL JAVA_STATIC -// EXPECT NEXT: DependencyOuterJavaClass.staticPrivateField.field: FINAL JAVA_STATIC PRIVATE : FINAL JAVA_STATIC PRIVATE +// EXPECT NEXT: DependencyOuterJavaClass.staticPrivateField.field: JAVA_STATIC PRIVATE : JAVA_STATIC PRIVATE // DependencyOuterJavaClass.staticPrivateField: FINAL JAVA_STATIC PRIVATE : FINAL JAVA_STATIC PRIVATE // DependencyOuterJavaClass.staticPrivateMethod: FINAL JAVA_STATIC PRIVATE : FINAL JAVA_STATIC PRIVATE -// EXPECT NEXT: DependencyOuterJavaClass.staticProtectedField.field: FINAL JAVA_STATIC PROTECTED : FINAL JAVA_STATIC PROTECTED +// EXPECT NEXT: DependencyOuterJavaClass.staticProtectedField.field: JAVA_STATIC PROTECTED : JAVA_STATIC PROTECTED // DependencyOuterJavaClass.staticProtectedField: FINAL JAVA_STATIC PROTECTED : FINAL JAVA_STATIC PROTECTED // DependencyOuterJavaClass.staticProtectedMethod: FINAL JAVA_STATIC PROTECTED : FINAL JAVA_STATIC PROTECTED -// EXPECT NEXT: DependencyOuterJavaClass.staticPublicField.field: FINAL JAVA_STATIC PUBLIC : FINAL JAVA_STATIC PUBLIC +// EXPECT NEXT: DependencyOuterJavaClass.staticPublicField.field: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC // DependencyOuterJavaClass.staticPublicField: FINAL JAVA_STATIC PUBLIC : FINAL JAVA_STATIC PUBLIC // DependencyOuterJavaClass.staticPublicMethod: FINAL JAVA_STATIC PUBLIC : FINAL JAVA_STATIC PUBLIC // DependencyOuterJavaClass.synchronizedFun: OPEN : JAVA_SYNCHRONIZED -// EXPECT NEXT: DependencyOuterJavaClass.transientField.field: FINAL : FINAL +// EXPECT NEXT: DependencyOuterJavaClass.transientField.field: JAVA_TRANSIENT : JAVA_TRANSIENT // DependencyOuterJavaClass.transientField: FINAL : FINAL JAVA_TRANSIENT -// EXPECT NEXT: DependencyOuterJavaClass.volatileField.field: FINAL : FINAL +// EXPECT NEXT: DependencyOuterJavaClass.volatileField.field: JAVA_VOLATILE : JAVA_VOLATILE // DependencyOuterJavaClass.volatileField: FINAL : FINAL JAVA_VOLATILE // DependencyOuterJavaClass: OPEN PUBLIC : PUBLIC // DependencyOuterKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC