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