Enforce ACC_VOLATILE/ACC_FINAL exclusivity
diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt index 5aba2b8..557d4a6 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/ResolverAAImpl.kt
@@ -263,8 +263,11 @@ Origin.SYNTHETIC -> existingJavaModifiers(declaration) } - private fun existingJavaModifiers(declaration: KSDeclaration): Set<Modifier> = - declaration.modifiers.filter { it in javaModifiers }.toSet() + private fun existingJavaModifiers(declaration: KSDeclaration): Set<Modifier> { + val modifiers = declaration.modifiers.filter { it in javaModifiers }.toSet() + // According to the JVM specification, ACC_VOLATILE and ACC_FINAL are mutually exclusive, so we defer to ACC_VOLATILE + return if (isVolatile(declaration)) modifiers - Modifier.FINAL else modifiers + } private fun visibilityModifier(declaration: KSDeclaration): Modifier? = when (declaration.getVisibility()) { // TODO: getVisibility might be inlined here or simplified here. @@ -303,8 +306,17 @@ else -> null } + private fun isVolatile(declaration: KSDeclaration): Boolean = when (declaration.origin) { + Origin.KOTLIN -> declaration.annotations.any { it.resolvesTo(JVM_VOLATILE_ANNOTATION_FQN) } + Origin.KOTLIN_LIB, Origin.JAVA_LIB -> volatileModifierIfApplicableTo(declaration) != null + Origin.JAVA -> declaration.modifiers.contains(Modifier.JAVA_VOLATILE) + Origin.SYNTHETIC -> false + } + private fun finalModifierIfApplicableTo(declaration: KSDeclaration): Modifier? = when (declaration.origin) { - Origin.KOTLIN if declaration !is KSBackingField && !declaration.isOpen() -> Modifier.FINAL + // According to the JVM specification, ACC_VOLATILE and ACC_FINAL are mutually exclusive, so we defer to ACC_VOLATILE + Origin.KOTLIN if declaration !is KSBackingField && !declaration.isOpen() && !isVolatile(declaration) -> + Modifier.FINAL else -> null }
diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt index 118fb08..901faa1 100644 --- a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt
@@ -90,7 +90,7 @@ ?: "${parentDeclaration?.qualifiedName?.asString()}.${simpleName.asString()}" val modifiersSignature = modifiers.map { it.toString() }.sorted().joinToString(" ") val extras = resolver.effectiveJavaModifiers(this).map { it.toString() }.sorted().joinToString(" ").trim() - return "$id: $modifiersSignature".trim() + " : " + extras + return ("$id: $modifiersSignature".trim() + " : " + extras).trim() } } }
diff --git a/kotlin-analysis-api/testData/javaModifiers.kt b/kotlin-analysis-api/testData/javaModifiers.kt index 85fdf6c..1531b44 100644 --- a/kotlin-analysis-api/testData/javaModifiers.kt +++ b/kotlin-analysis-api/testData/javaModifiers.kt
@@ -51,7 +51,7 @@ // EXPECT NEXT: DependencyOuterJavaClass.transientField.field: JAVA_TRANSIENT : JAVA_TRANSIENT // DependencyOuterJavaClass.transientField: FINAL : FINAL JAVA_TRANSIENT // EXPECT NEXT: DependencyOuterJavaClass.volatileField.field: JAVA_VOLATILE : JAVA_VOLATILE -// DependencyOuterJavaClass.volatileField: FINAL : FINAL JAVA_VOLATILE +// DependencyOuterJavaClass.volatileField: FINAL : JAVA_VOLATILE // DependencyOuterJavaClass: OPEN PUBLIC : PUBLIC // DependencyOuterKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC // DependencyOuterKotlinClass.Companion.<init>: FINAL PRIVATE : FINAL PRIVATE @@ -78,7 +78,7 @@ // EXPECT NEXT: DependencyOuterKotlinClass.transientProperty.field: FINAL PRIVATE : FINAL PRIVATE // DependencyOuterKotlinClass.transientProperty: FINAL PUBLIC : FINAL JAVA_TRANSIENT PUBLIC // EXPECT NEXT: DependencyOuterKotlinClass.volatileProperty.field: PRIVATE : PRIVATE -// DependencyOuterKotlinClass.volatileProperty: FINAL PUBLIC : FINAL JAVA_VOLATILE PUBLIC +// DependencyOuterKotlinClass.volatileProperty: FINAL PUBLIC : JAVA_VOLATILE PUBLIC // DependencyOuterKotlinClass: OPEN PUBLIC : PUBLIC // HasTypeAliasFuns: Modifiers: [] // HasTypeAliasFuns: Visibility: PUBLIC @@ -102,6 +102,11 @@ // EXPECT NEXT: OuterJavaClass.staticPublicField.field: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC // OuterJavaClass.staticPublicField: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC // OuterJavaClass.staticPublicMethod: JAVA_STATIC PUBLIC : JAVA_STATIC PUBLIC +// OuterJavaClass.synchronizedFun: JAVA_SYNCHRONIZED : JAVA_SYNCHRONIZED +// EXPECT NEXT: OuterJavaClass.transientField.field: JAVA_TRANSIENT : JAVA_TRANSIENT +// OuterJavaClass.transientField: JAVA_TRANSIENT : JAVA_TRANSIENT +// EXPECT NEXT: OuterJavaClass.volatileField.field: JAVA_VOLATILE : JAVA_VOLATILE +// OuterJavaClass.volatileField: JAVA_VOLATILE : JAVA_VOLATILE // OuterJavaClass: PUBLIC : PUBLIC // OuterKotlinClass.<init>: FINAL PUBLIC : FINAL PUBLIC // OuterKotlinClass.Companion.<init>: FINAL PUBLIC : FINAL PUBLIC @@ -126,7 +131,7 @@ // OuterKotlinClass.mutableProperty: : FINAL PUBLIC // OuterKotlinClass.synchronizedFun: : FINAL JAVA_SYNCHRONIZED PUBLIC // EXPECT CURRENT: OuterKotlinClass.transientProperty: : FINAL JAVA_TRANSIENT PUBLIC -// EXPECT CURRENT: OuterKotlinClass.volatileProperty: : FINAL JAVA_VOLATILE PUBLIC +// EXPECT CURRENT: OuterKotlinClass.volatileProperty: : JAVA_VOLATILE PUBLIC // EXPECT NEXT: OuterKotlinClass.transientProperty.field: FINAL PRIVATE : FINAL JAVA_TRANSIENT PRIVATE // EXPECT NEXT: OuterKotlinClass.transientProperty: : FINAL PUBLIC // EXPECT NEXT: OuterKotlinClass.volatileProperty.field: PRIVATE : JAVA_VOLATILE PRIVATE @@ -262,6 +267,9 @@ protected static String staticProtectedField; private static void staticPrivateMethod() {} private static String staticPrivateField; + transient String transientField = ""; + volatile String volatileField = ""; + synchronized String synchronizedFun() { return ""; } } // FILE: OuterKotlinClass.kt typealias CustomJvmStatic=JvmStatic