Merge commit '8f575aa213d7d4325677f365848e4f1e57c34e05' into dev-release
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
index 3ba3b8b..37c4087 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.keepanno.ast.KeepEdgeException;
import com.android.tools.r8.keepanno.ast.KeepItemPattern;
import com.android.tools.r8.keepanno.ast.KeepItemPattern.Builder;
-import com.android.tools.r8.keepanno.ast.KeepMembersPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
import com.android.tools.r8.keepanno.ast.KeepPreconditions;
@@ -170,9 +169,7 @@
}
if (methodName != null) {
itemBuilder.setMembersPattern(
- KeepMembersPattern.builder()
- .addMethodPattern(KeepMethodPattern.builder().setNamePattern(methodName).build())
- .build());
+ KeepMethodPattern.builder().setNamePattern(methodName).build());
}
KeepTarget target = KeepTarget.builder().setItem(itemBuilder.build()).build();
parent.accept(target);
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 1641d8d..0e96364 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
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.asm;
-import com.android.tools.r8.keepanno.annotations.KeepConstants;
import com.android.tools.r8.keepanno.annotations.KeepConstants.Edge;
import com.android.tools.r8.keepanno.annotations.KeepConstants.Target;
import com.android.tools.r8.keepanno.ast.KeepConsequences;
import com.android.tools.r8.keepanno.ast.KeepEdge;
-import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
+import com.android.tools.r8.keepanno.ast.KeepItemPattern;
+import com.android.tools.r8.keepanno.ast.KeepMembersPattern;
+import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern.KeepMethodNameExactPattern;
+import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
import com.android.tools.r8.keepanno.ast.KeepPreconditions;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
import com.android.tools.r8.keepanno.utils.Unimplemented;
@@ -45,68 +47,58 @@
private void writeConsequences(AnnotationVisitor visitor, KeepConsequences consequences) {
assert !consequences.isEmpty();
String ignoredArrayValueName = null;
- AnnotationVisitor arrayVisitor = visitor.visitArray(KeepConstants.Edge.consequences);
+ AnnotationVisitor arrayVisitor = visitor.visitArray(Edge.consequences);
consequences.forEachTarget(
target -> {
AnnotationVisitor targetVisitor =
- arrayVisitor.visitAnnotation(ignoredArrayValueName, KeepConstants.Target.DESCRIPTOR);
+ arrayVisitor.visitAnnotation(ignoredArrayValueName, Target.DESCRIPTOR);
// No options imply keep all.
if (!target.getOptions().isKeepAll()) {
throw new Unimplemented();
}
- target
- .getItem()
- .match(
- () -> {
- throw new Unimplemented();
- },
- clazz -> {
- KeepQualifiedClassNamePattern namePattern = clazz.getClassNamePattern();
- if (namePattern.isExact()) {
- Type typeConstant = Type.getType(namePattern.getExactDescriptor());
- targetVisitor.visit(KeepConstants.Target.classConstant, typeConstant);
- } else {
- throw new Unimplemented();
- }
- if (!clazz.getExtendsPattern().isAny()) {
- throw new Unimplemented();
- }
- if (clazz.getMembersPattern().isNone()) {
- // Default is "no methods".
- } else if (clazz.getMembersPattern().isAll()) {
- throw new Unimplemented();
- } else {
- clazz
- .getMembersPattern()
- .forEach(
- field -> {
- throw new Unimplemented();
- },
- method -> {
- KeepMethodNamePattern methodNamePattern = method.getNamePattern();
- methodNamePattern.match(
- () -> {
- throw new Unimplemented();
- },
- exactMethodName -> {
- targetVisitor.visit(Target.methodName, exactMethodName);
- return null;
- });
- if (!method.getAccessPattern().isAny()) {
- throw new Unimplemented();
- }
- if (!method.getReturnTypePattern().isAny()) {
- throw new Unimplemented();
- }
- if (!method.getParametersPattern().isAny()) {
- throw new Unimplemented();
- }
- });
- }
- return null;
- });
+ KeepItemPattern item = target.getItem();
+ if (item.isAny()) {
+ throw new Unimplemented();
+ }
+ KeepQualifiedClassNamePattern namePattern = item.getClassNamePattern();
+ if (namePattern.isExact()) {
+ Type typeConstant = Type.getType(namePattern.getExactDescriptor());
+ targetVisitor.visit(Target.classConstant, typeConstant);
+ } else {
+ throw new Unimplemented();
+ }
+ if (!item.getExtendsPattern().isAny()) {
+ throw new Unimplemented();
+ }
+ writeMembers(item.getMembersPattern(), targetVisitor);
targetVisitor.visitEnd();
});
arrayVisitor.visitEnd();
}
+
+ private void writeMembers(KeepMembersPattern membersPattern, AnnotationVisitor targetVisitor) {
+ if (membersPattern.isNone()) {
+ // Default is "no methods".
+ return;
+ }
+ if (membersPattern.isAll()) {
+ throw new Unimplemented();
+ }
+ KeepMethodPattern method = membersPattern.asMethod();
+ KeepMethodNameExactPattern exactMethodName = method.getNamePattern().asExact();
+ if (exactMethodName != null) {
+ targetVisitor.visit(Target.methodName, exactMethodName.getName());
+ } else {
+ throw new Unimplemented();
+ }
+ if (!method.getAccessPattern().isAny()) {
+ throw new Unimplemented();
+ }
+ if (!method.getReturnTypePattern().isAny()) {
+ throw new Unimplemented();
+ }
+ if (!method.getParametersPattern().isAny()) {
+ throw new Unimplemented();
+ }
+ }
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
index 4da44aa..5271837 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
@@ -25,12 +25,12 @@
* CONDITION ::= ITEM_PATTERN
*
* CONSEQUENCES ::= TARGET+
- * TARGET ::= any | OPTIONS ITEM_PATTERN
+ * TARGET ::= any | OPTIONS ITEM_PATTERN // TODO(b/248408342): What options are on target 'any'?
* OPTIONS ::= keep-all | OPTION+
* OPTION ::= shrinking | optimizing | obfuscating | access-modifying
*
- * ITEM_PATTERN ::= any | CLASS_PATTERN
- * CLASS_PATTERN ::= QUALIFIED_CLASS_NAME_PATTERN extends EXTENDS_PATTERN { MEMBERS_PATTERN }
+ * ITEM_PATTERN ::=
+ * class QUALIFIED_CLASS_NAME_PATTERN extends EXTENDS_PATTERN { MEMBERS_PATTERN }
*
* TYPE_PATTERN ::= any
* PACKAGE_PATTERN ::= any | exact package-name
@@ -38,7 +38,7 @@
* UNQUALIFIED_CLASS_NAME_PATTERN ::= any | exact simple-class-name
* EXTENDS_PATTERN ::= any | QUALIFIED_CLASS_NAME_PATTERN
*
- * MEMBERS_PATTERN ::= none | all | METHOD_PATTERN*
+ * MEMBERS_PATTERN ::= none | all | METHOD_PATTERN
*
* METHOD_PATTERN
* ::= METHOD_ACCESS_PATTERN
@@ -49,7 +49,7 @@
* METHOD_ACCESS_PATTERN ::= any
* METHOD_NAME_PATTERN ::= any | exact method-name
* METHOD_RETURN_TYPE_PATTERN ::= void | TYPE_PATTERN
- * METHOD_PARAMETERS_PATTERN ::= any | none | TYPE_PATTERN+
+ * METHOD_PARAMETERS_PATTERN ::= any | none | (TYPE_PATTERN+)
* </pre>
*/
public final class KeepEdge {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepExtendsPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepExtendsPattern.java
index b6b0fd7..02c8768 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepExtendsPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepExtendsPattern.java
@@ -7,7 +7,7 @@
public abstract class KeepExtendsPattern {
public static KeepExtendsPattern any() {
- return KeepExtendsAnyPattern.getInstance();
+ return Any.getInstance();
}
public static class Builder {
@@ -17,24 +17,21 @@
private Builder() {}
public Builder any() {
- pattern = KeepExtendsAnyPattern.getInstance();
+ pattern = Any.getInstance();
return this;
}
public Builder classPattern(KeepQualifiedClassNamePattern pattern) {
- this.pattern = new KeepExtendsClassPattern(pattern);
+ this.pattern = new Some(pattern);
return this;
}
}
- private static class KeepExtendsAnyPattern extends KeepExtendsPattern {
+ private static class Any extends KeepExtendsPattern {
- private static KeepExtendsAnyPattern INSTANCE = null;
+ private static final Any INSTANCE = new Any();
- public static KeepExtendsAnyPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepExtendsAnyPattern();
- }
+ public static Any getInstance() {
return INSTANCE;
}
@@ -59,11 +56,11 @@
}
}
- private static class KeepExtendsClassPattern extends KeepExtendsPattern {
+ private static class Some extends KeepExtendsPattern {
private final KeepQualifiedClassNamePattern pattern;
- public KeepExtendsClassPattern(KeepQualifiedClassNamePattern pattern) {
+ public Some(KeepQualifiedClassNamePattern pattern) {
assert pattern != null;
this.pattern = pattern;
}
@@ -81,7 +78,7 @@
if (o == null || getClass() != o.getClass()) {
return false;
}
- KeepExtendsClassPattern that = (KeepExtendsClassPattern) o;
+ Some that = (Some) o;
return pattern.equals(that.pattern);
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
deleted file mode 100644
index 8de46e1..0000000
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.keepanno.ast;
-
-public class KeepFieldPattern extends KeepMemberPattern {
-
- private KeepFieldPattern() {}
-
- public boolean isAnyField() {
- return false;
- }
-}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
index e5b0987..68c5c17 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.keepanno.ast;
import java.util.Objects;
-import java.util.function.Function;
-import java.util.function.Supplier;
/**
* A pattern for matching items in the program.
@@ -17,16 +15,18 @@
* classes or it is a pattern on members. The distinction is defined by having a "none" member
* pattern.
*/
-public abstract class KeepItemPattern {
+public class KeepItemPattern {
+
+ public static KeepItemPattern any() {
+ KeepItemPattern any = builder().any().build();
+ assert any.isAny();
+ return any;
+ }
public static Builder builder() {
return new Builder();
}
- public static KeepItemPattern any() {
- return KeepItemAnyPattern.getInstance();
- }
-
public static class Builder {
private KeepQualifiedClassNamePattern classNamePattern;
@@ -61,128 +61,71 @@
if (classNamePattern == null) {
throw new KeepEdgeException("Class pattern must define a class name pattern.");
}
- if (classNamePattern.isAny() && extendsPattern.isAny() && membersPattern.isAll()) {
- return KeepItemPattern.any();
- }
- return new KeepClassPattern(classNamePattern, extendsPattern, membersPattern);
+ return new KeepItemPattern(classNamePattern, extendsPattern, membersPattern);
}
}
- private static class KeepItemAnyPattern extends KeepItemPattern {
+ private final KeepQualifiedClassNamePattern qualifiedClassPattern;
+ private final KeepExtendsPattern extendsPattern;
+ private final KeepMembersPattern membersPattern;
+ // TODO: class annotations
- private static KeepItemAnyPattern INSTANCE = null;
+ private KeepItemPattern(
+ KeepQualifiedClassNamePattern qualifiedClassPattern,
+ KeepExtendsPattern extendsPattern,
+ KeepMembersPattern membersPattern) {
+ assert qualifiedClassPattern != null;
+ assert extendsPattern != null;
+ assert membersPattern != null;
+ this.qualifiedClassPattern = qualifiedClassPattern;
+ this.extendsPattern = extendsPattern;
+ this.membersPattern = membersPattern;
+ }
- public static KeepItemAnyPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepItemAnyPattern();
- }
- return INSTANCE;
- }
+ public boolean isAny() {
+ return qualifiedClassPattern.isAny() && extendsPattern.isAny() && membersPattern.isAll();
+ }
- @Override
- public boolean isAny() {
+ public KeepQualifiedClassNamePattern getClassNamePattern() {
+ return qualifiedClassPattern;
+ }
+
+ public KeepExtendsPattern getExtendsPattern() {
+ return extendsPattern;
+ }
+
+ public KeepMembersPattern getMembersPattern() {
+ return membersPattern;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
return true;
}
-
- @Override
- public <T> T match(Supplier<T> onAny, Function<KeepClassPattern, T> onItem) {
- return onAny.get();
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
}
-
- @Override
- public boolean equals(Object obj) {
- return this == obj;
- }
-
- @Override
- public int hashCode() {
- return System.identityHashCode(this);
- }
-
- @Override
- public String toString() {
- return "*";
- }
+ KeepItemPattern that = (KeepItemPattern) obj;
+ return qualifiedClassPattern.equals(that.qualifiedClassPattern)
+ && extendsPattern.equals(that.extendsPattern)
+ && membersPattern.equals(that.membersPattern);
}
- public static class KeepClassPattern extends KeepItemPattern {
-
- private final KeepQualifiedClassNamePattern qualifiedClassPattern;
- private final KeepExtendsPattern extendsPattern;
- private final KeepMembersPattern membersPattern;
- // TODO: class annotations
-
- private KeepClassPattern(
- KeepQualifiedClassNamePattern qualifiedClassPattern,
- KeepExtendsPattern extendsPattern,
- KeepMembersPattern membersPattern) {
- assert qualifiedClassPattern != null;
- assert extendsPattern != null;
- assert membersPattern != null;
- this.qualifiedClassPattern = qualifiedClassPattern;
- this.extendsPattern = extendsPattern;
- this.membersPattern = membersPattern;
- }
-
- @Override
- public boolean isAny() {
- return qualifiedClassPattern.isAny() && extendsPattern.isAny() && membersPattern.isAll();
- }
-
- @Override
- public <T> T match(Supplier<T> onAny, Function<KeepClassPattern, T> onItem) {
- if (isAny()) {
- return onAny.get();
- } else {
- return onItem.apply(this);
- }
- }
-
- public KeepQualifiedClassNamePattern getClassNamePattern() {
- return qualifiedClassPattern;
- }
-
- public KeepExtendsPattern getExtendsPattern() {
- return extendsPattern;
- }
-
- public KeepMembersPattern getMembersPattern() {
- return membersPattern;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- KeepClassPattern that = (KeepClassPattern) obj;
- return qualifiedClassPattern.equals(that.qualifiedClassPattern)
- && extendsPattern.equals(that.extendsPattern)
- && membersPattern.equals(that.membersPattern);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(qualifiedClassPattern, extendsPattern, membersPattern);
- }
-
- @Override
- public String toString() {
- return "KeepClassPattern{"
- + "qualifiedClassPattern="
- + qualifiedClassPattern
- + ", extendsPattern="
- + extendsPattern
- + ", membersPattern="
- + membersPattern
- + '}';
- }
+ @Override
+ public int hashCode() {
+ return Objects.hash(qualifiedClassPattern, extendsPattern, membersPattern);
}
- public abstract boolean isAny();
-
- public abstract <T> T match(Supplier<T> onAny, Function<KeepClassPattern, T> onItem);
+ @Override
+ public String toString() {
+ return "KeepClassPattern{"
+ + "qualifiedClassPattern="
+ + qualifiedClassPattern
+ + ", extendsPattern="
+ + extendsPattern
+ + ", membersPattern="
+ + membersPattern
+ + '}';
+ }
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
deleted file mode 100644
index bd716e9..0000000
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.keepanno.ast;
-
-public abstract class KeepMemberPattern {
-
- public static KeepMemberPattern anyMember() {
- return KeepMemberAnyPattern.getInstance();
- }
-
- private static class KeepMemberAnyPattern extends KeepMemberPattern {
- private static KeepMemberAnyPattern INSTANCE = null;
-
- public static KeepMemberAnyPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepMemberAnyPattern();
- }
- return INSTANCE;
- }
-
- @Override
- public boolean isAnyMember() {
- return true;
- }
- }
-
- public boolean isAnyMember() {
- return false;
- }
-
- abstract static class Builder<T extends Builder<T>> {
-
- public abstract T self();
-
- Builder() {}
- }
-}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMembersPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMembersPattern.java
index be5af32..64e1b25 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMembersPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMembersPattern.java
@@ -3,77 +3,22 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.ast;
-import com.android.tools.r8.keepanno.utils.Unimplemented;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
public abstract class KeepMembersPattern {
- public static Builder builder() {
- return new Builder();
- }
-
public static KeepMembersPattern none() {
- return KeepMembersNonePattern.getInstance();
+ return None.getInstance();
}
public static KeepMembersPattern all() {
- return KeepMembersAllPattern.getInstance();
+ return All.getInstance();
}
- public static class Builder {
+ private static class All extends KeepMembersPattern {
- private boolean anyMethod = false;
- private boolean anyField = false;
- private List<KeepMethodPattern> methods = new ArrayList<>();
- private List<KeepFieldPattern> fields = new ArrayList<>();
+ private static final All INSTANCE = new All();
- public Builder addMethodPattern(KeepMethodPattern methodPattern) {
- if (anyMethod) {
- return this;
- }
- if (methodPattern.isAnyMethod()) {
- methods.clear();
- anyMethod = true;
- }
- methods.add(methodPattern);
- return this;
- }
-
- public Builder addFieldPattern(KeepFieldPattern fieldPattern) {
- if (anyField) {
- return this;
- }
- if (fieldPattern.isAnyField()) {
- fields.clear();
- anyField = true;
- }
- fields.add(fieldPattern);
- return this;
- }
-
- public KeepMembersPattern build() {
- if (methods.isEmpty() && fields.isEmpty()) {
- return KeepMembersPattern.none();
- }
- if (anyMethod && anyField) {
- return KeepMembersPattern.all();
- }
- return new KeepMembersSomePattern(methods, fields);
- }
- }
-
- private static class KeepMembersAllPattern extends KeepMembersPattern {
-
- private static KeepMembersAllPattern INSTANCE = null;
-
- public static KeepMembersAllPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepMembersAllPattern();
- }
+ public static All getInstance() {
return INSTANCE;
}
@@ -83,16 +28,6 @@
}
@Override
- public boolean isNone() {
- return true;
- }
-
- @Override
- public void forEach(Consumer<KeepFieldPattern> onField, Consumer<KeepMethodPattern> onMethod) {
- throw new Unimplemented("Should this include all and none?");
- }
-
- @Override
public boolean equals(Object obj) {
return this == obj;
}
@@ -108,33 +43,20 @@
}
}
- private static class KeepMembersNonePattern extends KeepMembersPattern {
+ private static class None extends KeepMembersPattern {
- private static KeepMembersNonePattern INSTANCE = null;
+ private static final None INSTANCE = new None();
- public static KeepMembersNonePattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepMembersNonePattern();
- }
+ public static None getInstance() {
return INSTANCE;
}
@Override
- public boolean isAll() {
- return false;
- }
-
- @Override
public boolean isNone() {
return true;
}
@Override
- public void forEach(Consumer<KeepFieldPattern> onField, Consumer<KeepMethodPattern> onMethod) {
- throw new Unimplemented("Should this include all and none?");
- }
-
- @Override
public boolean equals(Object obj) {
return this == obj;
}
@@ -150,69 +72,21 @@
}
}
- private static class KeepMembersSomePattern extends KeepMembersPattern {
+ KeepMembersPattern() {}
- private final List<KeepMethodPattern> methods;
- private final List<KeepFieldPattern> fields;
-
- private KeepMembersSomePattern(List<KeepMethodPattern> methods, List<KeepFieldPattern> fields) {
- assert !methods.isEmpty() || !fields.isEmpty();
- this.methods = methods;
- this.fields = fields;
- }
-
- @Override
- public boolean isAll() {
- // Since there is at least one none-all field or method this is not a match all.
- return false;
- }
-
- @Override
- public boolean isNone() {
- // Since there is at least one field or method this is not a match none.
- return false;
- }
-
- @Override
- public void forEach(Consumer<KeepFieldPattern> onField, Consumer<KeepMethodPattern> onMethod) {
- fields.forEach(onField);
- methods.forEach(onMethod);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- KeepMembersSomePattern that = (KeepMembersSomePattern) obj;
- return methods.equals(that.methods) && fields.equals(that.fields);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(methods, fields);
- }
-
- @Override
- public String toString() {
- return "KeepMembersSomePattern{"
- + "methods={"
- + methods.stream().map(Object::toString).collect(Collectors.joining(", "))
- + "}, fields={"
- + fields.stream().map(Object::toString).collect(Collectors.joining(", "))
- + "}}";
- }
+ public boolean isAll() {
+ return false;
}
- private KeepMembersPattern() {}
+ public boolean isNone() {
+ return false;
+ }
- public abstract boolean isAll();
+ public final boolean isMethod() {
+ return asMethod() != null;
+ }
- public abstract boolean isNone();
-
- public abstract void forEach(
- Consumer<KeepFieldPattern> onField, Consumer<KeepMethodPattern> onMethod);
+ public KeepMethodPattern asMethod() {
+ return null;
+ }
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java
index fd0fd3e..4417b2e 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.ast;
+
// TODO: finish this.
public abstract class KeepMethodAccessPattern {
@@ -14,12 +15,9 @@
private static class Any extends KeepMethodAccessPattern {
- private static Any INSTANCE = null;
+ private static final Any INSTANCE = new Any();
private static Any getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new Any();
- }
return INSTANCE;
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodNamePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodNamePattern.java
index 6dc373d..8203d56 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodNamePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodNamePattern.java
@@ -3,13 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.ast;
-import java.util.function.Function;
-import java.util.function.Supplier;
public abstract class KeepMethodNamePattern {
public static KeepMethodNamePattern any() {
- return KeepMethodNameAnyPattern.getInstance();
+ return Any.getInstance();
}
public static KeepMethodNamePattern initializer() {
@@ -23,29 +21,27 @@
private KeepMethodNamePattern() {}
public boolean isAny() {
- return match(() -> true, ignore -> false);
+ return false;
}
- public boolean isExact() {
- return match(() -> false, ignore -> true);
+ public final boolean isExact() {
+ return asExact() != null;
}
- ;
- public abstract <T> T match(Supplier<T> onAny, Function<String, T> onExact);
+ public KeepMethodNameExactPattern asExact() {
+ return null;
+ }
- private static class KeepMethodNameAnyPattern extends KeepMethodNamePattern {
- private static KeepMethodNameAnyPattern INSTANCE = null;
+ private static class Any extends KeepMethodNamePattern {
+ private static final Any INSTANCE = new Any();
- public static KeepMethodNameAnyPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepMethodNameAnyPattern();
- }
+ public static Any getInstance() {
return INSTANCE;
}
@Override
- public <T> T match(Supplier<T> onAny, Function<String, T> onExact) {
- return onAny.get();
+ public boolean isAny() {
+ return true;
}
@Override
@@ -64,7 +60,7 @@
}
}
- private static class KeepMethodNameExactPattern extends KeepMethodNamePattern {
+ public static class KeepMethodNameExactPattern extends KeepMethodNamePattern {
private final String name;
public KeepMethodNameExactPattern(String name) {
@@ -73,8 +69,12 @@
}
@Override
- public <T> T match(Supplier<T> onAny, Function<String, T> onExact) {
- return onExact.apply(name);
+ public KeepMethodNameExactPattern asExact() {
+ return this;
+ }
+
+ public String getName() {
+ return name;
}
@Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodParametersPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodParametersPattern.java
index 83b4606..29442ff 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodParametersPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodParametersPattern.java
@@ -5,8 +5,6 @@
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
-import java.util.function.Supplier;
public abstract class KeepMethodParametersPattern {
@@ -15,61 +13,68 @@
}
public static KeepMethodParametersPattern none() {
- return None.getInstance();
+ return Some.EMPTY_INSTANCE;
}
private KeepMethodParametersPattern() {}
- public abstract <T> T match(Supplier<T> onAny, Function<List<KeepTypePattern>, T> onList);
-
public boolean isAny() {
- return match(() -> true, params -> false);
+ return false;
}
- private static class None extends KeepMethodParametersPattern {
- private static None INSTANCE = null;
+ public boolean isList() {
+ return asList() != null;
+ }
- public static None getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new None();
+ public List<KeepTypePattern> asList() {
+ return null;
+ }
+
+ private static class Some extends KeepMethodParametersPattern {
+
+ private static final Some EMPTY_INSTANCE = new Some(Collections.emptyList());
+
+ private final List<KeepTypePattern> parameterPatterns;
+
+ private Some(List<KeepTypePattern> parameterPatterns) {
+ assert parameterPatterns != null;
+ this.parameterPatterns = parameterPatterns;
+ }
+
+ @Override
+ public List<KeepTypePattern> asList() {
+ return parameterPatterns;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
}
- return INSTANCE;
- }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
- @Override
- public <T> T match(Supplier<T> onAny, Function<List<KeepTypePattern>, T> onList) {
- return onList.apply(Collections.emptyList());
- }
-
- @Override
- public boolean equals(Object obj) {
- return this == obj;
+ Some that = (Some) o;
+ return parameterPatterns.equals(that.parameterPatterns);
}
@Override
public int hashCode() {
- return System.identityHashCode(this);
- }
-
- @Override
- public String toString() {
- return "()";
+ return parameterPatterns.hashCode();
}
}
private static class Any extends KeepMethodParametersPattern {
- private static Any INSTANCE = null;
+ private static final Any INSTANCE = new Any();
public static Any getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new Any();
- }
return INSTANCE;
}
@Override
- public <T> T match(Supplier<T> onAny, Function<List<KeepTypePattern>, T> onList) {
- return onAny.get();
+ public boolean isAny() {
+ return true;
}
@Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
index b3ec418..bec8102 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
@@ -5,13 +5,13 @@
import java.util.Objects;
-public final class KeepMethodPattern extends KeepMemberPattern {
+public final class KeepMethodPattern extends KeepMembersPattern {
public static Builder builder() {
return new Builder();
}
- public static class Builder extends KeepMemberPattern.Builder<Builder> {
+ public static class Builder {
private KeepMethodAccessPattern accessPattern = KeepMethodAccessPattern.any();
private KeepMethodNamePattern namePattern = null;
@@ -20,7 +20,6 @@
private Builder() {}
- @Override
public Builder self() {
return this;
}
@@ -74,8 +73,16 @@
this.parametersPattern = parametersPattern;
}
+ @Override
+ public KeepMethodPattern asMethod() {
+ return this;
+ }
+
public boolean isAnyMethod() {
- return false;
+ return accessPattern.isAny()
+ && namePattern.isAny()
+ && returnTypePattern.isAny()
+ && parametersPattern.isAny();
}
public KeepMethodAccessPattern getAccessPattern() {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodReturnTypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodReturnTypePattern.java
index f711bc0..ccfc183 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodReturnTypePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodReturnTypePattern.java
@@ -3,43 +3,43 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.ast;
-import java.util.function.Function;
-import java.util.function.Supplier;
public abstract class KeepMethodReturnTypePattern {
- private static SomeType ANY_TYPE_INSTANCE = null;
-
public static KeepMethodReturnTypePattern any() {
- if (ANY_TYPE_INSTANCE == null) {
- ANY_TYPE_INSTANCE = new SomeType(KeepTypePattern.any());
- }
- return ANY_TYPE_INSTANCE;
+ return SomeType.ANY_TYPE_INSTANCE;
}
public static KeepMethodReturnTypePattern voidType() {
return VoidType.getInstance();
}
- public abstract <T> T match(Supplier<T> onVoid, Function<KeepTypePattern, T> onType);
-
public boolean isAny() {
- return match(() -> false, KeepTypePattern::isAny);
+ return isType() && asType().isAny();
+ }
+
+ public boolean isVoid() {
+ return false;
+ }
+
+ public boolean isType() {
+ return asType() != null;
+ }
+
+ public KeepTypePattern asType() {
+ return null;
}
private static class VoidType extends KeepMethodReturnTypePattern {
- private static VoidType INSTANCE = null;
+ private static final VoidType INSTANCE = new VoidType();
public static VoidType getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new VoidType();
- }
return INSTANCE;
}
@Override
- public <T> T match(Supplier<T> onVoid, Function<KeepTypePattern, T> onType) {
- return onVoid.get();
+ public boolean isVoid() {
+ return true;
}
@Override
@@ -60,6 +60,8 @@
private static class SomeType extends KeepMethodReturnTypePattern {
+ private static final SomeType ANY_TYPE_INSTANCE = new SomeType(KeepTypePattern.any());
+
private final KeepTypePattern typePattern;
private SomeType(KeepTypePattern typePattern) {
@@ -68,8 +70,8 @@
}
@Override
- public <T> T match(Supplier<T> onVoid, Function<KeepTypePattern, T> onType) {
- return onType.apply(typePattern);
+ public KeepTypePattern asType() {
+ return typePattern;
}
@Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepOptions.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepOptions.java
index 21b7487..8e1b2e9 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepOptions.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepOptions.java
@@ -12,6 +12,7 @@
import java.util.stream.Collectors;
public final class KeepOptions {
+ private static final KeepOptions ALLOW_NONE_INSTANCE = new KeepOptions(ImmutableSet.of());
public boolean isKeepAll() {
return allowedOptions.isEmpty();
@@ -25,9 +26,6 @@
}
public static KeepOptions keepAll() {
- if (ALLOW_NONE_INSTANCE == null) {
- ALLOW_NONE_INSTANCE = new KeepOptions(ImmutableSet.of());
- }
return ALLOW_NONE_INSTANCE;
}
@@ -97,8 +95,6 @@
}
}
- private static KeepOptions ALLOW_NONE_INSTANCE = null;
-
private final ImmutableSet<KeepOption> allowedOptions;
private KeepOptions(ImmutableSet<KeepOption> options) {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java
index 7d23490..6042930 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java
@@ -10,11 +10,11 @@
}
public static KeepPackagePattern any() {
- return KeepPackageAnyPattern.getInstance();
+ return Any.getInstance();
}
public static KeepPackagePattern top() {
- return KeepPackageTopPattern.getInstance();
+ return Top.getInstance();
}
public static KeepPackagePattern exact(String fullPackage) {
@@ -26,20 +26,17 @@
private KeepPackagePattern pattern;
public Builder any() {
- pattern = KeepPackageAnyPattern.getInstance();
+ pattern = Any.getInstance();
return this;
}
public Builder top() {
- pattern = KeepPackageTopPattern.getInstance();
+ pattern = Top.getInstance();
return this;
}
public Builder exact(String fullPackage) {
- pattern =
- fullPackage.isEmpty()
- ? KeepPackagePattern.top()
- : new KeepPackageExactPattern(fullPackage);
+ pattern = fullPackage.isEmpty() ? KeepPackagePattern.top() : new Exact(fullPackage);
return this;
}
@@ -51,18 +48,15 @@
}
}
- private static final class KeepPackageAnyPattern extends KeepPackagePattern {
+ private static final class Any extends KeepPackagePattern {
- private static KeepPackageAnyPattern INSTANCE = null;
+ private static final Any INSTANCE = new Any();
- public static KeepPackageAnyPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepPackageAnyPattern();
- }
+ public static Any getInstance() {
return INSTANCE;
}
- private KeepPackageAnyPattern() {}
+ private Any() {}
@Override
public boolean isAny() {
@@ -95,18 +89,15 @@
}
}
- private static final class KeepPackageTopPattern extends KeepPackageExactPattern {
+ private static final class Top extends Exact {
- private static KeepPackageTopPattern INSTANCE = null;
+ private static final Top INSTANCE = new Top();
- public static KeepPackageTopPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepPackageTopPattern();
- }
+ public static Top getInstance() {
return INSTANCE;
}
- private KeepPackageTopPattern() {
+ private Top() {
super("");
}
@@ -126,11 +117,11 @@
}
}
- public static class KeepPackageExactPattern extends KeepPackagePattern {
+ private static class Exact extends KeepPackagePattern {
private final String fullPackage;
- private KeepPackageExactPattern(String fullPackage) {
+ private Exact(String fullPackage) {
assert fullPackage != null;
this.fullPackage = fullPackage;
// TODO: Verify valid package identifiers.
@@ -152,10 +143,6 @@
}
@Override
- public KeepPackageExactPattern asExact() {
- return this;
- }
-
public String getExactPackageAsString() {
return fullPackage;
}
@@ -168,7 +155,7 @@
if (o == null || getClass() != o.getClass()) {
return false;
}
- KeepPackageExactPattern that = (KeepPackageExactPattern) o;
+ Exact that = (Exact) o;
return fullPackage.equals(that.fullPackage);
}
@@ -189,7 +176,7 @@
public abstract boolean isExact();
- public KeepPackageExactPattern asExact() {
- return null;
+ public String getExactPackageAsString() {
+ throw new IllegalStateException();
}
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java
index f672013..dfba9f6 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java
@@ -34,19 +34,16 @@
}
public static KeepPreconditions always() {
- return KeepPreconditionsAlways.getInstance();
+ return Always.getInstance();
}
public abstract boolean isAlways();
- private static class KeepPreconditionsAlways extends KeepPreconditions {
+ private static class Always extends KeepPreconditions {
- private static KeepPreconditionsAlways INSTANCE = null;
+ private static final Always INSTANCE = new Always();
- public static KeepPreconditionsAlways getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepPreconditionsAlways();
- }
+ public static Always getInstance() {
return INSTANCE;
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java
index 97d01b9..ee7f3d9 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java
@@ -83,7 +83,7 @@
throw new KeepEdgeException("Attempt to obtain exact qualified type for inexact pattern");
}
return 'L'
- + packagePattern.asExact().getExactPackageAsString().replace('.', '/')
+ + packagePattern.getExactPackageAsString().replace('.', '/')
+ (packagePattern.isTop() ? "" : "/")
+ namePattern.asExact().getExactNameAsString()
+ ';';
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
index a790094..c7c24b5 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
@@ -10,12 +10,9 @@
}
private static class Any extends KeepTypePattern {
- private static Any INSTANCE = null;
+ private static final Any INSTANCE = new Any();
public static Any getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new Any();
- }
return INSTANCE;
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepUnqualfiedClassNamePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepUnqualfiedClassNamePattern.java
index c9ac380..f1fbd28 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepUnqualfiedClassNamePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepUnqualfiedClassNamePattern.java
@@ -10,7 +10,7 @@
}
public static KeepUnqualfiedClassNamePattern any() {
- return KeepClassNameAnyPattern.getInstance();
+ return Any.getInstance();
}
public static KeepUnqualfiedClassNamePattern exact(String className) {
@@ -22,7 +22,7 @@
private KeepUnqualfiedClassNamePattern pattern;
public Builder any() {
- pattern = KeepClassNameAnyPattern.getInstance();
+ pattern = Any.getInstance();
return this;
}
@@ -39,18 +39,15 @@
}
}
- private static class KeepClassNameAnyPattern extends KeepUnqualfiedClassNamePattern {
+ private static class Any extends KeepUnqualfiedClassNamePattern {
- private static KeepClassNameAnyPattern INSTANCE = null;
+ private static final Any INSTANCE = new Any();
- public static KeepClassNameAnyPattern getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new KeepClassNameAnyPattern();
- }
+ public static Any getInstance() {
return INSTANCE;
}
- private KeepClassNameAnyPattern() {}
+ private Any() {}
@Override
public boolean isAny() {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
index d9b75ae..3ab882f 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
@@ -5,8 +5,7 @@
import com.android.tools.r8.keepanno.ast.KeepConsequences;
import com.android.tools.r8.keepanno.ast.KeepEdge;
-import com.android.tools.r8.keepanno.ast.KeepFieldPattern;
-import com.android.tools.r8.keepanno.ast.KeepItemPattern.KeepClassPattern;
+import com.android.tools.r8.keepanno.ast.KeepItemPattern;
import com.android.tools.r8.keepanno.ast.KeepMembersPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodAccessPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
@@ -51,37 +50,29 @@
boolean[] hasAtLeastOneConditionalClause = new boolean[1];
preconditions.forEach(
condition -> {
- // The usage kind for a predicate is not expressible in keep rules, so it is
- // ignored.
- condition
- .getItemPattern()
- .match(
- () -> {
- // If the conditions is "any" then we ignore it for now (identity of
- // conjunction).
- return null;
- },
- conditionItem -> {
- hasAtLeastOneConditionalClause[0] = true;
- consequentRules.forEach(
- consequentItem -> {
- // Since conjunctions are not supported in keep rules, we expand them into
- // disjunctions so conservatively we keep the consequences if any one of
- // the preconditions hold.
- StringBuilder builder = new StringBuilder();
- if (!consequentItem.isMemberConsequent()
- || !conditionItem
- .getClassNamePattern()
- .equals(consequentItem.getHolderPattern())) {
- builder.append("-if ");
- printClassItem(builder, conditionItem);
- builder.append(' ');
- }
- printConsequentRule(builder, consequentItem);
- ruleConsumer.accept(builder.toString());
- });
- return null;
- });
+ KeepItemPattern conditionItem = condition.getItemPattern();
+ // If the conditions is "any" then we ignore it for now (identity of conjunction).
+ if (conditionItem.isAny()) {
+ return;
+ }
+ hasAtLeastOneConditionalClause[0] = true;
+ consequentRules.forEach(
+ consequentItem -> {
+ // Since conjunctions are not supported in keep rules, we expand them into
+ // disjunctions so conservatively we keep the consequences if any one of
+ // the preconditions hold.
+ StringBuilder builder = new StringBuilder();
+ if (!consequentItem.isMemberOnlyConsequent()
+ || !conditionItem
+ .getClassNamePattern()
+ .equals(consequentItem.getHolderPattern())) {
+ builder.append("-if ");
+ printItem(builder, conditionItem);
+ builder.append(' ');
+ }
+ printConsequentRule(builder, consequentItem);
+ ruleConsumer.accept(builder.toString());
+ });
});
assert !(preconditions.isAlways() && hasAtLeastOneConditionalClause[0]);
if (!hasAtLeastOneConditionalClause[0]) {
@@ -92,7 +83,7 @@
}
private static StringBuilder printConsequentRule(StringBuilder builder, ItemRule rule) {
- if (rule.isMemberConsequent()) {
+ if (rule.isMemberOnlyConsequent()) {
builder.append("-keepclassmembers");
} else {
builder.append("-keep");
@@ -105,8 +96,7 @@
return builder.append(" ").append(rule.getKeepRuleForItem());
}
- private static StringBuilder printClassItem(
- StringBuilder builder, KeepClassPattern clazzPattern) {
+ private static StringBuilder printItem(StringBuilder builder, KeepItemPattern clazzPattern) {
builder.append("class ");
printClassName(builder, clazzPattern.getClassNamePattern());
if (!clazzPattern.getExtendsPattern().isAny()) {
@@ -119,19 +109,12 @@
if (members.isAll()) {
return builder.append(" { *; }");
}
- builder.append(" {");
- members.forEach(
- field -> printField(builder.append(' '), field),
- method -> printMethod(builder.append(' '), method));
- return builder.append(" }");
- }
-
- private static StringBuilder printField(StringBuilder builder, KeepFieldPattern field) {
- if (field.isAnyField()) {
- return builder.append("<fields>;");
- } else {
- throw new Unimplemented();
+ if (members.isMethod()) {
+ builder.append(" {");
+ printMethod(builder.append(' '), members.asMethod());
+ return builder.append(" }");
}
+ throw new Unimplemented();
}
private static StringBuilder printMethod(StringBuilder builder, KeepMethodPattern methodPattern) {
@@ -148,24 +131,31 @@
private static StringBuilder printParameters(
StringBuilder builder, KeepMethodParametersPattern parametersPattern) {
- return parametersPattern.match(
- () -> builder.append("(***)"),
- list ->
- builder
- .append('(')
- .append(list.stream().map(Object::toString).collect(Collectors.joining(", ")))
- .append(')'));
+ if (parametersPattern.isAny()) {
+ return builder.append("(***)");
+ }
+ return builder
+ .append('(')
+ .append(
+ parametersPattern.asList().stream()
+ .map(Object::toString)
+ .collect(Collectors.joining(", ")))
+ .append(')');
}
private static StringBuilder printMethodName(
StringBuilder builder, KeepMethodNamePattern namePattern) {
- return namePattern.match(() -> builder.append("*"), builder::append);
+ return namePattern.isAny()
+ ? builder.append("*")
+ : builder.append(namePattern.asExact().getName());
}
private static StringBuilder printReturnType(
StringBuilder builder, KeepMethodReturnTypePattern returnTypePattern) {
- return returnTypePattern.match(
- () -> builder.append("void"), typePattern -> printType(builder, typePattern));
+ if (returnTypePattern.isVoid()) {
+ return builder.append("void");
+ }
+ return printType(builder, returnTypePattern.asType());
}
private static StringBuilder printType(StringBuilder builder, KeepTypePattern typePattern) {
@@ -203,7 +193,7 @@
return builder;
}
assert packagePattern.isExact();
- return builder.append(packagePattern.asExact().getExactPackageAsString()).append('.');
+ return builder.append(packagePattern.getExactPackageAsString()).append('.');
}
private static StringBuilder printSimpleClassName(
@@ -240,24 +230,20 @@
this.options = target.getOptions();
}
- public boolean isMemberConsequent() {
- return target.getItem().match(() -> false, clazz -> !clazz.getMembersPattern().isNone());
+ public boolean isMemberOnlyConsequent() {
+ KeepItemPattern item = target.getItem();
+ return !item.isAny() && !item.getMembersPattern().isNone();
}
public KeepQualifiedClassNamePattern getHolderPattern() {
- return target
- .getItem()
- .match(KeepQualifiedClassNamePattern::any, KeepClassPattern::getClassNamePattern);
+ return target.getItem().getClassNamePattern();
}
public String getKeepRuleForItem() {
if (ruleLine == null) {
+ KeepItemPattern item = target.getItem();
ruleLine =
- target
- .getItem()
- .match(
- () -> "class * { *; }",
- clazz -> printClassItem(new StringBuilder(), clazz).toString());
+ item.isAny() ? "class * { *; }" : printItem(new StringBuilder(), item).toString();
}
return ruleLine;
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java b/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java
index 36bbaeb..58601a6 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.keepanno.ast.KeepEdge;
import com.android.tools.r8.keepanno.ast.KeepEdge.Builder;
import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepMembersPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
@@ -137,11 +136,8 @@
if (methodNameValue != null) {
String methodName = AnnotationStringValueVisitor.getString(methodNameValue);
itemBuilder.setMembersPattern(
- KeepMembersPattern.builder()
- .addMethodPattern(
- KeepMethodPattern.builder()
- .setNamePattern(KeepMethodNamePattern.exact(methodName))
- .build())
+ KeepMethodPattern.builder()
+ .setNamePattern(KeepMethodNamePattern.exact(methodName))
.build());
}
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
index 65351f8..1ba0b22 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
@@ -215,11 +215,14 @@
if (arg.equals("info")) {
return DiagnosticsLevel.INFO;
}
+ if (arg.equals("none")) {
+ return DiagnosticsLevel.NONE;
+ }
errorHandler.accept(
new StringDiagnostic(
"Invalid diagnostics level '"
+ arg
- + "'. Valid levels are 'error', 'warning' and 'info'.",
+ + "'. Valid levels are 'error', 'warning', 'info' and 'none'.",
origin));
return null;
diff --git a/src/main/java/com/android/tools/r8/DiagnosticsLevel.java b/src/main/java/com/android/tools/r8/DiagnosticsLevel.java
index 9f9d26a..a022b0d 100644
--- a/src/main/java/com/android/tools/r8/DiagnosticsLevel.java
+++ b/src/main/java/com/android/tools/r8/DiagnosticsLevel.java
@@ -8,5 +8,6 @@
public enum DiagnosticsLevel {
ERROR,
WARNING,
- INFO
+ INFO,
+ NONE
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 751b635..f85f8d5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -184,7 +184,9 @@
this.printer = printer;
this.codeRewriter = new CodeRewriter(appView);
this.assertionErrorTwoArgsConstructorRewriter =
- new AssertionErrorTwoArgsConstructorRewriter(appView);
+ appView.options().desugarState.isOn()
+ ? new AssertionErrorTwoArgsConstructorRewriter(appView)
+ : null;
this.classInitializerDefaultsOptimization =
new ClassInitializerDefaultsOptimization(appView, this);
this.stringOptimizer = new StringOptimizer(appView);
@@ -1341,9 +1343,11 @@
timing.begin("Natural Int Loop Remover");
naturalIntLoopRemover.run(appView, code);
timing.end();
- timing.begin("Rewrite AssertionError");
- assertionErrorTwoArgsConstructorRewriter.rewrite(code, methodProcessingContext);
- timing.end();
+ if (assertionErrorTwoArgsConstructorRewriter != null) {
+ timing.begin("Rewrite AssertionError");
+ assertionErrorTwoArgsConstructorRewriter.rewrite(code, methodProcessingContext);
+ timing.end();
+ }
timing.begin("Run CSE");
codeRewriter.commonSubexpressionElimination(code);
timing.end();
@@ -1522,6 +1526,11 @@
timing.end();
}
+ timing.begin("Redundant catch/rethrow elimination");
+ codeRewriter.optimizeRedundantCatchRethrowInstructions(code);
+ timing.end();
+ previous = printMethod(code, "IR after redundant catch/rethrow elimination (SSA)", previous);
+
if (assumeInserter != null) {
timing.begin("Remove assume instructions");
CodeRewriter.removeAssumeInstructions(appView, code);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 3d9b8d2..6314197 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -3070,6 +3070,123 @@
return changed;
}
+ private boolean isPotentialTrivialRethrowValue(Value exceptionValue) {
+ if (exceptionValue.hasDebugUsers()) {
+ return false;
+ }
+ if (exceptionValue.hasUsers()) {
+ if (exceptionValue.hasPhiUsers()
+ || !exceptionValue.hasSingleUniqueUser()
+ || !exceptionValue.singleUniqueUser().isThrow()) {
+ return false;
+ }
+ } else if (exceptionValue.numberOfPhiUsers() != 1) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isSingleHandlerTrivial(BasicBlock firstBlock, IRCode code) {
+ InstructionListIterator instructionIterator = firstBlock.listIterator(code);
+ Instruction instruction = instructionIterator.next();
+ if (!instruction.isMoveException()) {
+ // A catch handler which doesn't use its exception is not going to be a trivial rethrow.
+ return false;
+ }
+ Value exceptionValue = instruction.outValue();
+ if (!isPotentialTrivialRethrowValue(exceptionValue)) {
+ return false;
+ }
+ while (instructionIterator.hasNext()) {
+ instruction = instructionIterator.next();
+ BasicBlock currentBlock = instruction.getBlock();
+ if (instruction.isGoto()) {
+ BasicBlock nextBlock = instruction.asGoto().getTarget();
+ int predecessorIndex = nextBlock.getPredecessors().indexOf(currentBlock);
+ Value phiAliasOfExceptionValue = null;
+ for (Phi phi : nextBlock.getPhis()) {
+ Value operand = phi.getOperand(predecessorIndex);
+ if (exceptionValue == operand) {
+ phiAliasOfExceptionValue = phi;
+ break;
+ }
+ }
+ if (phiAliasOfExceptionValue != null) {
+ if (!isPotentialTrivialRethrowValue(phiAliasOfExceptionValue)) {
+ return false;
+ }
+ exceptionValue = phiAliasOfExceptionValue;
+ }
+ instructionIterator = nextBlock.listIterator(code);
+ } else if (instruction.isThrow()) {
+ List<Value> throwValues = instruction.inValues();
+ assert throwValues.size() == 1;
+ if (throwValues.get(0) != exceptionValue) {
+ return false;
+ }
+ CatchHandlers<BasicBlock> currentHandlers = currentBlock.getCatchHandlers();
+ if (!currentHandlers.isEmpty()) {
+ // This is the case where our trivial catch handler has catch handler(s). For now, we
+ // will only treat our block as trivial if all its catch handlers are also trivial.
+ // Note: it is possible that we could "bridge" a trivial handler, where we take the
+ // handlers of the handler and bring them up to replace the trivial handler. Example:
+ // catch (Throwable t) {
+ // try { throw t; } catch(Throwable abc) { foo(abc); }
+ // }
+ // could turn into:
+ // catch (Throwable abc) {
+ // foo(abc);
+ // }
+ // However this gets significantly harder when you have to consider non-matching guard
+ // types.
+ for (CatchHandler<BasicBlock> handler : currentHandlers) {
+ if (!isSingleHandlerTrivial(handler.getTarget(), code)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } else {
+ // Any other instructions in the catch handler means it's not trivial, and thus we can't
+ // elide.
+ return false;
+ }
+ }
+ throw new Unreachable("Triviality check should always return before the loop terminates");
+ }
+
+ // Find any case where we have a catch followed immediately and only by a rethrow. This is extra
+ // code doing what the JVM does automatically and can be safely elided.
+ public void optimizeRedundantCatchRethrowInstructions(IRCode code) {
+ ListIterator<BasicBlock> blockIterator = code.listIterator();
+ boolean hasUnlinkedCatchHandlers = false;
+ while (blockIterator.hasNext()) {
+ BasicBlock blockWithHandlers = blockIterator.next();
+ if (blockWithHandlers.hasCatchHandlers()) {
+ boolean allHandlersAreTrivial = true;
+ for (CatchHandler<BasicBlock> handler : blockWithHandlers.getCatchHandlers()) {
+ if (!isSingleHandlerTrivial(handler.target, code)) {
+ allHandlersAreTrivial = false;
+ break;
+ }
+ }
+ // We need to ensure all handlers are trivial to unlink, since if one is non-trivial, and
+ // its guard is a parent type to a trivial one, removing the trivial catch will result in
+ // us hitting the non-trivial catch. This could be avoided by more sophisticated type
+ // analysis.
+ if (allHandlersAreTrivial) {
+ hasUnlinkedCatchHandlers = true;
+ for (CatchHandler<BasicBlock> handler : blockWithHandlers.getCatchHandlers()) {
+ handler.getTarget().unlinkCatchHandler();
+ }
+ }
+ }
+ }
+ if (hasUnlinkedCatchHandlers) {
+ code.removeUnreachableBlocks();
+ }
+ }
+
// Find all instructions that always throw, split the block after each such instruction and follow
// it with a block throwing a null value (which should result in NPE). Note that this throw is not
// expected to be ever reached, but is intended to satisfy verifier.
diff --git a/src/main/java/com/android/tools/r8/utils/Reporter.java b/src/main/java/com/android/tools/r8/utils/Reporter.java
index 65103ac..d2aa075 100644
--- a/src/main/java/com/android/tools/r8/utils/Reporter.java
+++ b/src/main/java/com/android/tools/r8/utils/Reporter.java
@@ -81,6 +81,8 @@
abort = new AbortException(diagnostic);
clientHandler.error(diagnostic);
break;
+ case NONE:
+ break;
default:
throw new Unreachable();
}
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardModifyDiagnosticsLevelTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardModifyDiagnosticsLevelTest.java
index 568c66f..faa47f1 100644
--- a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardModifyDiagnosticsLevelTest.java
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardModifyDiagnosticsLevelTest.java
@@ -101,7 +101,10 @@
.assertErrorsMatch(errorMatchers())
.assertWarningsMatch(warningMatchers())
.assertInfosMatch(infoMatchers()));
- assertTrue(mappedLevel == DiagnosticsLevel.INFO || mappedLevel == DiagnosticsLevel.WARNING);
+ assertTrue(
+ mappedLevel == DiagnosticsLevel.INFO
+ || mappedLevel == DiagnosticsLevel.WARNING
+ || mappedLevel == DiagnosticsLevel.NONE);
} catch (CompilationFailedException e) {
assertEquals(mappedLevel, DiagnosticsLevel.ERROR);
}
diff --git a/src/test/java/com/android/tools/r8/diagnostics/ModifyDiagnosticsLevelTest.java b/src/test/java/com/android/tools/r8/diagnostics/ModifyDiagnosticsLevelTest.java
index 9f20b7d..239a0f6 100644
--- a/src/test/java/com/android/tools/r8/diagnostics/ModifyDiagnosticsLevelTest.java
+++ b/src/test/java/com/android/tools/r8/diagnostics/ModifyDiagnosticsLevelTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DiagnosticsLevel;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.diagnostic.internal.MissingDefinitionsDiagnosticImpl;
@@ -84,6 +85,24 @@
}
}
+ @Test
+ public void testWarningToNone() throws CompilationFailedException {
+ testForR8(Backend.DEX)
+ .addProgramClasses(TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules("-ignorewarnings")
+ .setDiagnosticsLevelModifier(
+ (level, diagnostic) -> {
+ if (level == DiagnosticsLevel.WARNING
+ && diagnostic instanceof MissingDefinitionsDiagnosticImpl
+ && diagnostic.getDiagnosticMessage().startsWith(MISSING_CLASS_MESSAGE_PREFIX)) {
+ return DiagnosticsLevel.NONE;
+ }
+ return level;
+ })
+ .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages);
+ }
+
static class TestClass implements I {
public static void main(String[] args) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantcatchrethrowelimination/RedundantCatchRethrowEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantcatchrethrowelimination/RedundantCatchRethrowEliminationTest.java
new file mode 100644
index 0000000..7f7ef6d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantcatchrethrowelimination/RedundantCatchRethrowEliminationTest.java
@@ -0,0 +1,210 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.redundantcatchrethrowelimination;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.containsThrow;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RedundantCatchRethrowEliminationTest extends TestBase {
+
+ static final String EXPECTED =
+ StringUtils.lines(
+ "removableRethrow",
+ "trivialContext",
+ "complexRemovableRethrow",
+ "keptRethrow",
+ "nonTrivialContext",
+ "CloseableContext::close",
+ "complexKeptRethrow");
+
+ @Parameterized.Parameter() public TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testReference() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addProgramClasses(Main.class, TrivialClosableContext.class, ClosableContext.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ testForD8(parameters.getBackend())
+ .addProgramClasses(Main.class, TrivialClosableContext.class, ClosableContext.class)
+ .release()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::inspectD8);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class, TrivialClosableContext.class, ClosableContext.class)
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::inspectR8);
+ }
+
+ private void inspectD8(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(Main.class);
+ MethodSubject removableRethrowSubject =
+ classSubject.uniqueMethodWithOriginalName("removableRethrow");
+ assertThat(removableRethrowSubject, not(containsThrow()));
+ // Without whole-program optimizations, we can't get rid of the trivial closable context.close()
+ // call, which means that we can't remove the trivialContext throw.
+ MethodSubject complexRemovableRethrowSubject =
+ classSubject.uniqueMethodWithOriginalName("complexRemovableRethrow");
+ assertThat(complexRemovableRethrowSubject, not(containsThrow()));
+
+ MethodSubject keptRethrowSubject = classSubject.uniqueMethodWithOriginalName("keptRethrow");
+ assertThat(keptRethrowSubject, containsThrow());
+ MethodSubject nonTrivialContextSubject =
+ classSubject.uniqueMethodWithOriginalName("nonTrivialContext");
+ assertThat(nonTrivialContextSubject, containsThrow());
+ MethodSubject complexKeptRethrowSubject =
+ classSubject.uniqueMethodWithOriginalName("complexKeptRethrow");
+ assertThat(complexKeptRethrowSubject, containsThrow());
+ }
+
+ private void inspectR8(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(Main.class);
+ MethodSubject removableRethrowSubject =
+ classSubject.uniqueMethodWithOriginalName("removableRethrow");
+ assertThat(removableRethrowSubject, not(containsThrow()));
+ MethodSubject trivialContextSubject =
+ classSubject.uniqueMethodWithOriginalName("trivialContext");
+ assertThat(trivialContextSubject, not(containsThrow()));
+ MethodSubject complexRemovableRethrowSubject =
+ classSubject.uniqueMethodWithOriginalName("complexRemovableRethrow");
+ assertThat(complexRemovableRethrowSubject, not(containsThrow()));
+
+ MethodSubject keptRethrowSubject = classSubject.uniqueMethodWithOriginalName("keptRethrow");
+ assertThat(keptRethrowSubject, containsThrow());
+ MethodSubject nonTrivialContextSubject =
+ classSubject.uniqueMethodWithOriginalName("nonTrivialContext");
+ assertThat(nonTrivialContextSubject, containsThrow());
+ MethodSubject complexKeptRethrowSubject =
+ classSubject.uniqueMethodWithOriginalName("complexKeptRethrow");
+ assertThat(complexKeptRethrowSubject, containsThrow());
+ }
+
+ public static class TrivialClosableContext implements java.io.Closeable {
+ @Override
+ public void close() {}
+ }
+
+ public static class ClosableContext implements java.io.Closeable {
+ @Override
+ public void close() {
+ System.out.println("CloseableContext::close");
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ removableRethrow();
+ trivialContext();
+ complexRemovableRethrow();
+ keptRethrow();
+ nonTrivialContext();
+ complexKeptRethrow();
+ }
+
+ @NeverInline
+ static void removableRethrow() {
+ try {
+ System.out.println("removableRethrow");
+ } catch (Throwable t) {
+ throw t;
+ }
+ }
+
+ @NeverInline
+ static void trivialContext() {
+ try (TrivialClosableContext unused = new TrivialClosableContext()) {
+ System.out.println("trivialContext");
+ }
+ }
+
+ @NeverInline
+ static void complexRemovableRethrow() {
+ try {
+ System.out.println("complexRemovableRethrow");
+ } catch (RuntimeException e) {
+ try {
+ throw e;
+ } catch (RuntimeException e2) {
+ throw e2;
+ } catch (Throwable t) {
+ throw t;
+ }
+ } catch (Throwable t) {
+ throw t;
+ }
+ }
+
+ @NeverInline
+ static void keptRethrow() {
+ try {
+ System.out.println("keptRethrow");
+ } catch (Throwable t) {
+ throw new RuntimeException("cause", t);
+ }
+ }
+
+ @NeverInline
+ static void nonTrivialContext() {
+ try (ClosableContext unused = new ClosableContext()) {
+ System.out.println("nonTrivialContext");
+ }
+ }
+
+ @NeverInline
+ static void complexKeptRethrow() {
+ try {
+ System.out.println("complexKeptRethrow");
+ } catch (RuntimeException e) {
+ try {
+ throw e;
+ } catch (RuntimeException e2) {
+ throw e2;
+ } catch (Throwable t) {
+ System.out.println("So that this can't be elided");
+ throw t;
+ }
+ } catch (Throwable t) {
+ throw t;
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
index bcdb8ed..0f07d76 100644
--- a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
@@ -170,13 +170,10 @@
}
private KeepMembersPattern defaultInitializerPattern() {
- return KeepMembersPattern.builder()
- .addMethodPattern(
- KeepMethodPattern.builder()
- .setNamePattern(KeepMethodNamePattern.initializer())
- .setParametersPattern(KeepMethodParametersPattern.none())
- .setReturnTypeVoid()
- .build())
+ return KeepMethodPattern.builder()
+ .setNamePattern(KeepMethodNamePattern.initializer())
+ .setParametersPattern(KeepMethodParametersPattern.none())
+ .setReturnTypeVoid()
.build();
}
}
diff --git a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
index 187a019..b6369de 100644
--- a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
+++ b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.keepanno.ast.KeepConsequences;
import com.android.tools.r8.keepanno.ast.KeepEdge;
import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepMembersPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
@@ -37,12 +36,10 @@
// Build the constructor target.
KeepMethodPattern constructorMethod =
KeepMethodPattern.builder().setNamePattern(KeepMethodNamePattern.exact("<init>")).build();
- KeepMembersPattern constructorMembers =
- KeepMembersPattern.builder().addMethodPattern(constructorMethod).build();
KeepItemPattern constructorItem =
KeepItemPattern.builder()
.setClassPattern(name)
- .setMembersPattern(constructorMembers)
+ .setMembersPattern(constructorMethod)
.build();
KeepTarget constructorTarget = KeepTarget.builder().setItem(constructorItem).build();
// The consequet set is the class an its constructor.
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertionerror/AssertionErrorRewriteTest.java b/src/test/java/com/android/tools/r8/rewrite/assertionerror/AssertionErrorRewriteTest.java
index f22208c..2fa9d11 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertionerror/AssertionErrorRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertionerror/AssertionErrorRewriteTest.java
@@ -3,11 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.rewrite.assertionerror;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +36,8 @@
|| parameters.getApiLevel().getLevel() >= AndroidApiLevel.J.getLevel();
}
- @Test public void d8() throws Exception {
+ @Test
+ public void d8() throws Exception {
assumeTrue(parameters.isDexRuntime());
testForD8()
.addProgramClasses(Main.class)
@@ -44,7 +47,30 @@
.assertSuccessWithOutputLines("message", "java.lang.RuntimeException: cause message");
}
- @Test public void r8() throws Exception {
+ @Test
+ public void d8NoDesugar() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ testForD8()
+ .addProgramClasses(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .disableDesugaring()
+ .compile()
+ // TODO(b/247596495): There should be no synthetics.
+ .inspect(
+ inspector ->
+ assertTrue(
+ inspector.allClasses().stream()
+ .noneMatch(
+ clazz ->
+ SyntheticItemsTestUtils.isExternalSynthetic(
+ clazz.getFinalReference()))))
+ .run(parameters.getRuntime(), Main.class)
+ // None of the VMs we have for testing is missing the two args constructor.
+ .assertSuccessWithOutputLines("message", "java.lang.RuntimeException: cause message");
+ }
+
+ @Test
+ public void r8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClasses(Main.class)
.addKeepMainRule(Main.class)