[KeepAnno] Add builder option for experimental keep annotations.
Bug: b/248408342
Change-Id: I22c54b8b2d9f8eb2833d1bdb9c5c4f2ab6685d36
diff --git a/build.gradle b/build.gradle
index abf8ddf..de83e21 100644
--- a/build.gradle
+++ b/build.gradle
@@ -67,7 +67,7 @@
sourceSets {
main {
java {
- srcDirs = ['src/main/java']
+ srcDirs = ['src/main/java', 'src/keepanno/java']
}
resources {
srcDirs "third_party/api_database/api_database"
@@ -75,7 +75,7 @@
}
main11 {
java {
- srcDirs = ['src/main/java']
+ srcDirs = ['src/main/java', 'src/keepanno/java']
}
resources {
srcDirs "third_party/api_database/api_database"
@@ -83,7 +83,7 @@
}
main17 {
java {
- srcDirs = ['src/main/java']
+ srcDirs = ['src/main/java', 'src/keepanno/java']
}
resources {
srcDirs "third_party/api_database/api_database"
@@ -213,7 +213,7 @@
idea {
sourceSets.all { SourceSet sources ->
module {
- if (sources.name == "main" || sources.name == "keepanno") {
+ if (sources.name == "main") {
sourceDirs += sources.java.srcDirs
outputDir sources.output.classesDirs[0]
} else {
@@ -320,8 +320,6 @@
keepannoCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
keepannoCompile "com.google.guava:guava:$guavaVersion"
- testCompile sourceSets.keepanno.output
- testRuntime sourceSets.keepanno.output
}
def r8LibPath = "$buildDir/libs/r8lib.jar"
@@ -1106,7 +1104,6 @@
task testJarSources(type: Jar, dependsOn: [testClasses, buildLibraryDesugarConversions]) {
archiveFileName = "r8testsbase.jar"
from sourceSets.test.output
- from sourceSets.keepanno.output
// We only want to include tests that use R8 when generating keep rules for applymapping.
include "com/android/tools/r8/**"
include "android/**"
@@ -2247,6 +2244,7 @@
test { task ->
+ dependsOn sourceSets.keepanno.output
dependsOn buildLibraryDesugarConversions
dependsOn getJarsFromSupportLibs
// R8.jar is required for running bootstrap tests.
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java
index 8872494..37713a9 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java
@@ -3,6 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.annotations;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
/**
* A binding of a keep item.
*
@@ -12,6 +17,8 @@
*
* <p>See KeepTarget for documentation on specifying an item pattern.
*/
+@Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.CLASS)
public @interface KeepBinding {
/** Name with which other bindings, conditions or targets can reference the bound item pattern. */
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepConstants.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepConstants.java
index c88085a..f37c3fc 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepConstants.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepConstants.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.annotations;
+
/**
* Utility class for referencing the various keep annotations and their structure.
*
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
index f3e97fa..515becd 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
@@ -29,11 +29,66 @@
public class KeepEdgeWriter implements Opcodes {
+ /** Annotation visitor interface to allow usage from tests without type conflicts in r8lib. */
+ public interface AnnotationVisitorInterface {
+ int version();
+
+ void visit(String name, Object value);
+
+ void visitEnum(String name, String descriptor, String value);
+
+ AnnotationVisitorInterface visitAnnotation(String name, String descriptor);
+
+ AnnotationVisitorInterface visitArray(String name);
+
+ void visitEnd();
+ }
+
+ private static AnnotationVisitor wrap(AnnotationVisitorInterface visitor) {
+ if (visitor == null) {
+ return null;
+ }
+ return new AnnotationVisitor(visitor.version()) {
+
+ @Override
+ public void visit(String name, Object value) {
+ visitor.visit(name, value);
+ }
+
+ @Override
+ public void visitEnum(String name, String descriptor, String value) {
+ visitor.visitEnum(name, descriptor, value);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+ AnnotationVisitorInterface v = visitor.visitAnnotation(name, descriptor);
+ return v == visitor ? this : wrap(v);
+ }
+
+ @Override
+ public AnnotationVisitor visitArray(String name) {
+ AnnotationVisitorInterface v = visitor.visitArray(name);
+ return v == visitor ? this : wrap(v);
+ }
+
+ @Override
+ public void visitEnd() {
+ visitor.visitEnd();
+ }
+ };
+ }
+
public static void writeEdge(KeepEdge edge, ClassVisitor visitor) {
- writeEdge(edge, visitor::visitAnnotation);
+ writeEdgeInternal(edge, visitor::visitAnnotation);
}
public static void writeEdge(
+ KeepEdge edge, BiFunction<String, Boolean, AnnotationVisitorInterface> getVisitor) {
+ writeEdgeInternal(edge, (descriptor, visible) -> wrap(getVisitor.apply(descriptor, visible)));
+ }
+
+ public static void writeEdgeInternal(
KeepEdge edge, BiFunction<String, Boolean, AnnotationVisitor> getVisitor) {
new KeepEdgeWriter().writeEdge(edge, getVisitor.apply(Edge.DESCRIPTOR, false));
}
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 0bf09ac..d017a2f 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -15,6 +15,9 @@
import com.android.tools.r8.inspector.Inspector;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.keepanno.asm.KeepEdgeReader;
+import com.android.tools.r8.keepanno.ast.KeepEdge;
+import com.android.tools.r8.keepanno.keeprules.KeepRuleExtractor;
import com.android.tools.r8.naming.SourceFileRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
@@ -53,6 +56,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Optional;
@@ -122,6 +126,7 @@
private final List<FeatureSplit> featureSplits = new ArrayList<>();
private String synthesizedClassPrefix = "";
private boolean enableMissingLibraryApiModeling = false;
+ private boolean enableExperimentalKeepAnnotations = false;
private final ProguardConfigurationParserOptions.Builder parserOptionsBuilder =
ProguardConfigurationParserOptions.builder().readEnvironment();
@@ -447,6 +452,12 @@
return self();
}
+ @Deprecated
+ public Builder setEnableExperimentalKeepAnnotations(boolean enable) {
+ this.enableExperimentalKeepAnnotations = enable;
+ return self();
+ }
+
@Override
protected InternalProgramOutputPathConsumer createProgramOutputConsumer(
Path path,
@@ -578,6 +589,9 @@
proguardConfigurationConsumerForTesting.accept(configurationBuilder);
}
amendWithRulesAndProvidersForInjarsAndMetaInf(reporter, parser);
+ // Extract out rules for keep annotations and amend the configuration.
+ // TODO(b/248408342): Remove this and parse annotations as part of R8 root-set & enqueuer.
+ extractKeepAnnotationRules(parser);
ProguardConfiguration configuration = configurationBuilder.build();
getAppBuilder().addFilteredLibraryArchives(configuration.getLibraryjars());
@@ -697,6 +711,32 @@
}
}
+ private void extractKeepAnnotationRules(ProguardConfigurationParser parser) {
+ if (!enableExperimentalKeepAnnotations) {
+ return;
+ }
+ try {
+ for (ProgramResourceProvider provider : getAppBuilder().getProgramResourceProviders()) {
+ for (ProgramResource resource : provider.getProgramResources()) {
+ if (resource.getKind() == Kind.CF) {
+ Set<KeepEdge> edges = KeepEdgeReader.readKeepEdges(resource.getBytes());
+ KeepRuleExtractor extractor =
+ new KeepRuleExtractor(
+ rule -> {
+ ProguardConfigurationSourceStrings source =
+ new ProguardConfigurationSourceStrings(
+ Collections.singletonList(rule), null, resource.getOrigin());
+ parser.parse(source);
+ });
+ edges.forEach(extractor::extract);
+ }
+ }
+ }
+ } catch (ResourceException e) {
+ throw getAppBuilder().getReporter().fatalError(new ExceptionDiagnostic(e));
+ }
+ }
+
// Internal for-testing method to add post-processors of the proguard configuration.
void addProguardConfigurationConsumerForTesting(Consumer<ProguardConfiguration.Builder> c) {
Consumer<ProguardConfiguration.Builder> oldConsumer = proguardConfigurationConsumerForTesting;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
index bd09578..8e19b25 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
@@ -48,7 +48,9 @@
}
public void addInlinableFieldMatchingPrecondition(DexField field) {
- inlinableFieldsInPrecondition.put(field, field);
+ if (inlinableFieldsInPrecondition != null) {
+ inlinableFieldsInPrecondition.put(field, field);
+ }
}
public Set<DexField> getAndClearInlinableFieldsMatchingPrecondition() {
diff --git a/src/main/keep.txt b/src/main/keep.txt
index 2213ce9..89105b4 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -51,3 +51,7 @@
}
# Test in this class is using the class name to fing the original .java file.
-keep class com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaringMethods
+
+# Keep everything in the annotations package of keepanno.
+# These are public API as they denote the supported annotations to be interpreted by R8.
+-keep class com.android.tools.r8.keepanno.annotations.** { *; }
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 34f8a0b..c4cb889 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.dexsplitter.SplitterTestBase.SplitRunner;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
+import com.android.tools.r8.keepanno.KeepEdgeAnnotationsTest;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.art.ArtProfileConsumer;
import com.android.tools.r8.profile.art.ArtProfileProvider;
@@ -713,6 +714,13 @@
return self();
}
+ public T enableExperimentalKeepAnnotations() throws IOException {
+ builder.addClasspathResourceProvider(
+ DirectoryClassFileProvider.fromDirectory(KeepEdgeAnnotationsTest.KEEP_ANNO_PATH));
+ builder.setEnableExperimentalKeepAnnotations(true);
+ return self();
+ }
+
public T enableProguardTestOptions() {
builder.setEnableTestProguardOptions();
return self();
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepAnnotationViaSuperTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepAnnotationViaSuperTest.java
index 5f2237d..3c09bff 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepAnnotationViaSuperTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepAnnotationViaSuperTest.java
@@ -22,7 +22,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,11 +53,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
- System.out.println(rules);
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutKeepAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.addKeepRuntimeVisibleAnnotations()
.setMinApi(parameters.getApiLevel())
@@ -78,19 +75,6 @@
UnusedAnno.class);
}
- public List<byte[]> getInputClassesWithoutKeepAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(Base.class), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepBindingTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepBindingTest.java
index c83340f..cd00198 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepBindingTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepBindingTest.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,10 +49,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepClassRules(A.class, B.class)
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
@@ -64,10 +62,9 @@
@Test
public void testWithRuleExtractionAndNoKeepOnClass() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
@@ -79,19 +76,6 @@
return ImmutableList.of(TestClass.class, A.class, B.class, C.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector, boolean expectB) {
assertThat(inspector.clazz(A.class), isPresent());
assertThat(inspector.clazz(A.class).uniqueMethodWithOriginalName("foo"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
index f99f3bf..f4411a6 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
@@ -18,8 +18,8 @@
import com.android.tools.r8.keepanno.annotations.KeepConstants.Edge;
import com.android.tools.r8.keepanno.asm.KeepEdgeReader;
import com.android.tools.r8.keepanno.asm.KeepEdgeWriter;
+import com.android.tools.r8.keepanno.asm.KeepEdgeWriter.AnnotationVisitorInterface;
import com.android.tools.r8.keepanno.ast.KeepEdge;
-import com.android.tools.r8.keepanno.keeprules.KeepRuleExtractor;
import com.android.tools.r8.keepanno.processor.KeepEdgeProcessor;
import com.android.tools.r8.keepanno.testsource.KeepClassAndDefaultConstructorSource;
import com.android.tools.r8.keepanno.testsource.KeepDependentFieldSource;
@@ -42,10 +42,13 @@
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.objectweb.asm.AnnotationVisitor;
+@Ignore("b/248408342: These test break on r8lib builds because of src&test using ASM classes.")
@RunWith(Parameterized.class)
public class KeepEdgeAnnotationsTest extends TestBase {
@@ -64,7 +67,7 @@
}
}
- private static final Path KEEP_ANNO_PATH =
+ public static final Path KEEP_ANNO_PATH =
Paths.get(ToolHelper.BUILD_DIR, "classes", "java", "keepanno");
private static List<Class<?>> getTestClasses() {
@@ -150,6 +153,46 @@
return transformed;
}
+ /** Wrapper to bridge ASM visitors when using the r8lib compiled version of the keepanno lib. */
+ private AnnotationVisitorInterface wrap(AnnotationVisitor visitor) {
+ if (visitor == null) {
+ return null;
+ }
+ return new AnnotationVisitorInterface() {
+ @Override
+ public int version() {
+ return KeepEdgeReader.ASM_VERSION;
+ }
+
+ @Override
+ public void visit(String name, Object value) {
+ visitor.visit(name, value);
+ }
+
+ @Override
+ public void visitEnum(String name, String descriptor, String value) {
+ visitor.visitEnum(name, descriptor, value);
+ }
+
+ @Override
+ public AnnotationVisitorInterface visitAnnotation(String name, String descriptor) {
+ AnnotationVisitor v = visitor.visitAnnotation(name, descriptor);
+ return v == visitor ? this : wrap(v);
+ }
+
+ @Override
+ public AnnotationVisitorInterface visitArray(String name) {
+ AnnotationVisitor v = visitor.visitArray(name);
+ return v == visitor ? this : wrap(v);
+ }
+
+ @Override
+ public void visitEnd() {
+ visitor.visitEnd();
+ }
+ };
+ }
+
@Test
public void testAsmReader() throws Exception {
assumeTrue(parameters.isCfRuntime());
@@ -169,7 +212,8 @@
@Override
public void visitEnd() {
for (KeepEdge edge : expectedEdges) {
- KeepEdgeWriter.writeEdge(edge, super::visitAnnotation);
+ KeepEdgeWriter.writeEdge(
+ edge, (desc, visible) -> wrap(super.visitAnnotation(desc, visible)));
}
super.visitEnd();
}
@@ -190,25 +234,15 @@
@Test
public void testExtractAndRun() throws Exception {
- List<String> rules = getKeepRulesForClass(source);
testForR8(parameters.getBackend())
- .addClasspathFiles(KEEP_ANNO_PATH)
+ .enableExperimentalKeepAnnotations()
.addProgramClassesAndInnerClasses(source)
- .addKeepRules(rules)
.addKeepMainRule(source)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), source)
.assertSuccessWithOutput(getExpected());
}
- public static List<String> getKeepRulesForClass(Class<?> clazz) throws IOException {
- Set<KeepEdge> keepEdges = KeepEdgeReader.readKeepEdges(ToolHelper.getClassAsBytes(clazz));
- List<String> rules = new ArrayList<>();
- KeepRuleExtractor extractor = new KeepRuleExtractor(rules::add);
- keepEdges.forEach(extractor::extract);
- return rules;
- }
-
private void checkSynthesizedKeepEdgeClass(CodeInspector inspector, Path data)
throws IOException {
String synthesizedEdgesClassName =
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarAnyClassTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarAnyClassTest.java
index 74da176..82feaed 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarAnyClassTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarAnyClassTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,10 +47,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
@@ -63,19 +61,6 @@
return ImmutableList.of(TestClass.class, A.class, B.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(A.class), isPresent());
assertThat(inspector.clazz(A.class).uniqueMethodWithOriginalName("foo"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java
index 922a3ce..f1f1f6b 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,10 +49,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
@@ -64,20 +62,6 @@
public List<Class<?>> getInputClasses() {
return ImmutableList.of(TestClass.class, A.class, B.class);
}
-
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(A.class), isPresent());
assertThat(inspector.clazz(A.class).uniqueMethodWithOriginalName("foo"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepInvalidTargetTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepInvalidTargetTest.java
index 6f95aa6..a9c7405 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepInvalidTargetTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepInvalidTargetTest.java
@@ -11,10 +11,18 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.keepanno.annotations.KeepOption;
import com.android.tools.r8.keepanno.annotations.KeepTarget;
import com.android.tools.r8.keepanno.annotations.UsesReflection;
+import com.android.tools.r8.keepanno.asm.KeepEdgeReader;
+import com.android.tools.r8.keepanno.ast.KeepEdge;
import com.android.tools.r8.keepanno.ast.KeepEdgeException;
+import com.android.tools.r8.keepanno.keeprules.KeepRuleExtractor;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
@@ -33,21 +41,30 @@
parameters.assertNoneRuntime();
}
+ private static List<String> extractRuleForClass(Class<?> clazz) throws IOException {
+ Set<KeepEdge> keepEdges = KeepEdgeReader.readKeepEdges(ToolHelper.getClassAsBytes(clazz));
+ List<String> rules = new ArrayList<>();
+ KeepRuleExtractor extractor = new KeepRuleExtractor(rules::add);
+ keepEdges.forEach(extractor::extract);
+ return rules;
+ }
+
private void assertThrowsWith(ThrowingRunnable fn, Matcher<String> matcher) {
try {
fn.run();
- fail("Expected run to fail");
} catch (KeepEdgeException e) {
assertThat(e.getMessage(), matcher);
+ return;
} catch (Throwable e) {
- fail("Expected run to fail with KeepEdgeException");
+ fail("Expected run to fail with KeepEdgeException, but failed with: " + e);
}
+ fail("Expected run to fail");
}
@Test
public void testInvalidClassDecl() throws Exception {
assertThrowsWith(
- () -> KeepEdgeAnnotationsTest.getKeepRulesForClass(MultipleClassDeclarations.class),
+ () -> extractRuleForClass(MultipleClassDeclarations.class),
allOf(
containsString("Multiple declarations"),
containsString("className"),
@@ -65,7 +82,7 @@
@Test
public void testInvalidExtendsDecl() throws Exception {
assertThrowsWith(
- () -> KeepEdgeAnnotationsTest.getKeepRulesForClass(MultipleExtendsDeclarations.class),
+ () -> extractRuleForClass(MultipleExtendsDeclarations.class),
allOf(
containsString("Multiple declarations"),
containsString("extendsClassName"),
@@ -86,7 +103,7 @@
@Test
public void testInvalidMemberDecl() throws Exception {
assertThrowsWith(
- () -> KeepEdgeAnnotationsTest.getKeepRulesForClass(MultipleMemberDeclarations.class),
+ () -> extractRuleForClass(MultipleMemberDeclarations.class),
allOf(containsString("field"), containsString("method")));
}
@@ -101,7 +118,7 @@
@Test
public void testInvalidOptionsDecl() throws Exception {
assertThrowsWith(
- () -> KeepEdgeAnnotationsTest.getKeepRulesForClass(MultipleOptionDeclarations.class),
+ () -> extractRuleForClass(MultipleOptionDeclarations.class),
allOf(containsString("options"), containsString("allow"), containsString("disallow")));
}
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java
index f4060f3..0bf08bc 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,10 +50,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
// The "all members" target will create an unused "all fields" rule.
@@ -68,19 +66,6 @@
return ImmutableList.of(TestClass.class, A.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) throws Exception {
assertThat(inspector.clazz(A.class).method(A.class.getMethod("foo")), isPresent());
// TODO(b/265892343): The extracted rule will match all params so this is incorrectly kept.
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepTargetClassAndMemberKindTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepTargetClassAndMemberKindTest.java
index 02e86ae..8e78dda 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepTargetClassAndMemberKindTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepTargetClassAndMemberKindTest.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,13 +48,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
- for (String rule : rules) {
- System.out.println(rule);
- }
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.allowUnusedProguardConfigurationRules()
@@ -68,19 +63,6 @@
return ImmutableList.of(TestClass.class, A.class, B.class, C.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(A.class), isPresent());
assertThat(inspector.clazz(B.class), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationTest.java
index d692791..39eea01 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,10 +47,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.allowUnusedProguardConfigurationRules()
@@ -64,19 +62,6 @@
return ImmutableList.of(TestClass.class, A.class, B.class, C.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(A.class), isPresent());
assertThat(inspector.clazz(B.class), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationWithAdditionalPreconditionTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationWithAdditionalPreconditionTest.java
index a9dc1f7..05c742a 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationWithAdditionalPreconditionTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionAnnotationWithAdditionalPreconditionTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,10 +47,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
@@ -63,19 +61,6 @@
return ImmutableList.of(TestClass.class, A.class, B.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(B.class), isPresent());
assertThat(inspector.clazz(B.class).uniqueMethodWithOriginalName("<init>"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
index bfc7fb5..5177150 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,10 +47,9 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
@@ -63,19 +61,6 @@
return ImmutableList.of(TestClass.class, A.class, B.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(A.class), isPresent());
assertThat(inspector.clazz(A.class).uniqueFieldWithOriginalName("classNameForB"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java
index ee605b0..ace719a 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -19,7 +18,6 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Field;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,15 +49,18 @@
@Test
public void testWithRuleExtraction() throws Exception {
- List<String> rules = getExtractedKeepRules();
- assertEquals(1, rules.size());
- assertThat(rules.get(0), containsString("context: " + descriptor(A.class) + "foo()V"));
- assertThat(rules.get(0), containsString("description: Keep the\\nstring-valued fields"));
testForR8(parameters.getBackend())
- .addProgramClassFileData(getInputClassesWithoutAnnotations())
- .addKeepRules(rules)
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
+ .compile()
+ .apply(
+ c -> {
+ String rules = c.getProguardConfiguration().getParsedConfiguration();
+ assertThat(rules, containsString("context: " + descriptor(A.class) + "foo()V"));
+ assertThat(rules, containsString("description: Keep the\\nstring-valued fields"));
+ })
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED)
.inspect(this::checkOutput);
@@ -69,19 +70,6 @@
return ImmutableList.of(TestClass.class, A.class);
}
- public List<byte[]> getInputClassesWithoutAnnotations() throws Exception {
- return KeepEdgeAnnotationsTest.getInputClassesWithoutKeepAnnotations(getInputClasses());
- }
-
- public List<String> getExtractedKeepRules() throws Exception {
- List<Class<?>> classes = getInputClasses();
- List<String> rules = new ArrayList<>();
- for (Class<?> clazz : classes) {
- rules.addAll(KeepEdgeAnnotationsTest.getKeepRulesForClass(clazz));
- }
- return rules;
- }
-
private void checkOutput(CodeInspector inspector) {
assertThat(inspector.clazz(A.class), isPresent());
assertThat(inspector.clazz(A.class).uniqueFieldWithOriginalName("fieldA"), isPresent());