From 14dcc28ba2dd066c3078a5f559d3ba3ea85be01c Mon Sep 17 00:00:00 2001 From: piazzesiNiccolo-GS <151659293+piazzesiNiccolo-GS@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:47:13 +0100 Subject: [PATCH] Reapply moved InterfaceUsageMarker to fx interface constant marking (#510) --- .../java/proguard/shrink/UsageMarker.java | 3 + .../kotlin/proguard/shrink/UsageMarkerTest.kt | 68 +++++++++++++++++++ docs/md/manual/releasenotes.md | 6 ++ 3 files changed, 77 insertions(+) diff --git a/base/src/main/java/proguard/shrink/UsageMarker.java b/base/src/main/java/proguard/shrink/UsageMarker.java index 27ef0b3a..61b18a81 100644 --- a/base/src/main/java/proguard/shrink/UsageMarker.java +++ b/base/src/main/java/proguard/shrink/UsageMarker.java @@ -129,6 +129,9 @@ public class UsageMarker new LocalVariableTypeUsageMarker(classUsageMarker) )))); + // Second Interface Usage marking, this is necessary for marking interface constants that are not directly referenced + // (e.g. interfaces only referenced through annotations). See https://github.com/Guardsquare/proguard/issues/508. + programClassPool.classesAccept(new InterfaceUsageMarker(classUsageMarker)); if (configuration.keepKotlinMetadata) { diff --git a/base/src/test/kotlin/proguard/shrink/UsageMarkerTest.kt b/base/src/test/kotlin/proguard/shrink/UsageMarkerTest.kt index 7fad8bf9..df4bf4eb 100644 --- a/base/src/test/kotlin/proguard/shrink/UsageMarkerTest.kt +++ b/base/src/test/kotlin/proguard/shrink/UsageMarkerTest.kt @@ -21,6 +21,74 @@ import proguard.testutils.RequiresJavaVersion import proguard.util.ProcessingFlagSetter import proguard.util.ProcessingFlags.DONT_SHRINK +class UsageMarkerTest : BehaviorSpec({ + Given("A class pool with interfaces only referenced through annotations") { + + val (programClassPool, _) = ClassPoolBuilder.fromSource( + JavaSource("MyInterface.java",""" + interface MyInterface {} + """.trimIndent()), + JavaSource("MyAnnotation.java",""" + import java.lang.annotation.RetentionPolicy; + import java.lang.annotation.Retention; + + @Retention(RetentionPolicy.RUNTIME) + @interface MyAnnotation { + Class value(); + } + """.trimIndent()), + JavaSource("MyImpl.java",""" + class MyImpl implements MyInterface {} + """.trimIndent()), + JavaSource("InterfaceTest.java", """ + import java.lang.reflect.Field; + + class InterfaceTest { + + @MyAnnotation(MyImpl.class) + String s; + + public static void main(String... args) throws Exception { + Field f = InterfaceTest.class.getDeclaredField("s"); + MyAnnotation annotation = f.getAnnotation(MyAnnotation.class); + Object obj = annotation.value().getDeclaredConstructor().newInstance(); + if (obj instanceof MyInterface) { + System.out.println("success"); + } else { + throw new Exception(obj.getClass() + " does not implement " + MyInterface.class); + } + } + } + """.trimIndent()) + ) + val implClass = programClassPool.getClass("MyImpl") + val main = programClassPool.getClass("InterfaceTest") + main.accept( + MultiClassVisitor(ProcessingFlagSetter(DONT_SHRINK), AllMemberVisitor( + ProcessingFlagSetter(DONT_SHRINK) + ))) + When("marking") { + val simpleUsageMarker = SimpleUsageMarker() + UsageMarker(Configuration()).mark(programClassPool,ClassPool(), ResourceFilePool(),simpleUsageMarker) + Then("The interface class should be marked as used.") { + val used = object : ConstantVisitor { + var used = false + override fun visitAnyConstant( + clazz: Clazz?, + constant: Constant? + ) { + used = used or simpleUsageMarker.isUsed(constant) + } + } + implClass.interfaceConstantsAccept(used) + used.used shouldBe true + + } + } + } + +}) + @RequiresJavaVersion(15) class Java15UsageMarkerTest : BehaviorSpec({ // Regression test for https://github.com/Guardsquare/proguard/issues/501 diff --git a/docs/md/manual/releasenotes.md b/docs/md/manual/releasenotes.md index 34e01791..8d5e957f 100644 --- a/docs/md/manual/releasenotes.md +++ b/docs/md/manual/releasenotes.md @@ -1,3 +1,9 @@ +## Version 7.8.2 + +### Bugfixes + +- Fix regression in marking of interface constants (#508). + ## Version 7.8.1 ### Bugfixes