Do not rebind field accesses if that would conflict with visibility.
This changes the assumption that field accesses are always dispatched to
an actual definition. Moving forward, your analysis has to make sure that
the field id is dispatched first.
This change also changes the semantics of some fields in AppInfoWithLiveness
to reflect this change.
Bug: 38187737
Change-Id: I221dac4ded6a6708d5bfc01bdd7a51a7b516294a
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index e6c2d00..b9173dd 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -6,6 +6,19 @@
import java.util.IdentityHashMap;
import java.util.Map;
+/**
+ * A GraphLense implements a virtual view on top of the graph, used to delay global rewrites until
+ * later IR processing stages.
+ * <p>
+ * Valid remappings are limited to the following operations:
+ * <ul>
+ * <li>Mapping a classes type to one of the super/subtypes.</li>
+ * <li>Renaming private methods/fields.</li>
+ * <li>Moving methods/fields to a super/subclass.</li>
+ * <li>Replacing method/field references by the same method/field on a super/subtype</li>
+ * </ul>
+ * Note that the latter two have to take visibility into account.
+ */
public abstract class GraphLense {
public static class Builder {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index b122d23..df5cb27 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -236,8 +236,7 @@
private boolean isFieldRead(DexEncodedField field, boolean isStatic) {
// Without live set information we cannot tell and assume true.
if (liveSet == null
- || isStatic && liveSet.staticFieldsRead.contains(field.field)
- || !isStatic && liveSet.instanceFieldsRead.contains(field.field)
+ || liveSet.fieldsRead.contains(field.field)
|| liveSet.pinnedItems.contains(field)) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index 88d371b..17da59b 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.optimize;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.Descriptor;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -98,11 +97,6 @@
return searchClass.type;
}
- private boolean isNotFromLibrary(Descriptor item) {
- DexClass clazz = appInfo.definitionFor(item.getHolder());
- return clazz != null && !clazz.isLibraryClass();
- }
-
private DexEncodedMethod virtualLookup(DexMethod method) {
return appInfo.lookupVirtualDefinition(method.getHolder(), method);
}
@@ -190,13 +184,23 @@
for (DexField field : fields) {
field = lense.lookupField(field, null);
DexEncodedField target = lookup.apply(field.getHolder(), field);
- // Rebind to the lowest library class or program class.
- if (target != null && target.field != field) {
+ // Rebind to the lowest library class or program class. Do not rebind accesses to fields that
+ // are not public, as this might lead to access violation errors.
+ if (target != null && target.field != field && isVisibleFromOtherClasses(target)) {
builder.map(field, validTargetFor(target.field, field, lookupTargetOnClass));
}
}
}
+ private boolean isVisibleFromOtherClasses(DexEncodedField field) {
+ // If the field is not public, the visibility on the class can not be a further constraint.
+ if (!field.accessFlags.isPublic()) {
+ return true;
+ }
+ // If the field is public, then a non-public holder class will further constrain visibility.
+ return appInfo.definitionFor(field.field.getHolder()).accessFlags.isPublic();
+ }
+
private static void privateMethodsCheck(DexProgramClass clazz, DexEncodedMethod method) {
throw new Unreachable("Direct invokes should not require forwarding.");
}
@@ -211,9 +215,9 @@
computeMethodRebinding(appInfo.staticInvokes, appInfo::lookupStaticTarget,
DexClass::findDirectTarget, DexProgramClass::addStaticMethod);
- computeFieldRebinding(Sets.union(appInfo.staticFieldsRead, appInfo.staticFieldsWritten),
+ computeFieldRebinding(Sets.union(appInfo.staticFieldReads, appInfo.staticFieldWrites),
appInfo::lookupStaticTarget, DexClass::findStaticTarget);
- computeFieldRebinding(Sets.union(appInfo.instanceFieldsRead, appInfo.instanceFieldsWritten),
+ computeFieldRebinding(Sets.union(appInfo.instanceFieldReads, appInfo.instanceFieldWrites),
appInfo::lookupInstanceTarget, DexClass::findInstanceTarget);
return builder.build(lense, appInfo.dexItemFactory);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 2dab755..abdda65 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -37,6 +37,7 @@
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import java.util.ArrayDeque;
+import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
@@ -47,6 +48,7 @@
import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -856,9 +858,8 @@
}
private Set<DexField> collectFields(Map<DexType, Set<DexField>> map) {
- Set<DexField> set = Sets.newIdentityHashSet();
- map.values().forEach(set::addAll);
- return set;
+ return map.values().stream().flatMap(Collection::stream)
+ .collect(Collectors.toCollection(Sets::newIdentityHashSet));
}
Set<DexField> collectInstanceFieldsRead() {
@@ -877,6 +878,32 @@
return Collections.unmodifiableSet(collectFields(staticFieldsWritten));
}
+ private Set<DexField> collectReachedFields(Map<DexType, Set<DexField>> map,
+ Function<DexField, DexField> lookup) {
+ return map.values().stream().flatMap(set -> set.stream().map(lookup))
+ .collect(Collectors.toCollection(Sets::newIdentityHashSet));
+ }
+
+ private DexField tryLookupInstanceField(DexField field) {
+ DexEncodedField target = appInfo.lookupInstanceTarget(field.clazz, field);
+ return target == null ? field : target.field;
+ }
+
+ private DexField tryLookupStaticField(DexField field) {
+ DexEncodedField target = appInfo.lookupStaticTarget(field.clazz, field);
+ return target == null ? field : target.field;
+ }
+
+ Set<DexField> collectFieldsRead() {
+ return Sets.union(collectReachedFields(instanceFieldsRead, this::tryLookupInstanceField),
+ collectReachedFields(staticFieldsRead, this::tryLookupStaticField));
+ }
+
+ Set<DexField> collectFieldsWritten() {
+ return Sets.union(collectReachedFields(instanceFieldsWritten, this::tryLookupInstanceField),
+ collectReachedFields(staticFieldsWritten, this::tryLookupStaticField));
+ }
+
private static class Action {
final Kind kind;
@@ -981,31 +1008,29 @@
*/
final Set<DexField> liveFields;
/**
- * Set of all fields which are read. Combines {@link #instanceFieldsRead} and
- * {@link #staticFieldsRead}.
+ * Set of all fields which may be touched by a get operation. This is actual field definitions.
*/
public final Set<DexField> fieldsRead;
/**
- * Set of all fields which are written. Combines {@link #instanceFieldsWritten} and
- * {@link #staticFieldsWritten}.
+ * Set of all fields which may be touched by a put operation. This is actual field definitions.
*/
public final Set<DexField> fieldsWritten;
/**
- * Set of all instance fields which are read.
+ * Set of all field ids used in instance field reads.
*/
- public final Set<DexField> instanceFieldsRead;
+ public final Set<DexField> instanceFieldReads;
/**
- * Set of all instance fields which are written.
+ * Set of all field ids used in instance field writes.
*/
- public final Set<DexField> instanceFieldsWritten;
+ public final Set<DexField> instanceFieldWrites;
/**
- * Set of all static fields which are read.
+ * Set of all field ids used in static static field reads.
*/
- public final Set<DexField> staticFieldsRead;
+ public final Set<DexField> staticFieldReads;
/**
- * Set of all static fields which are written.
+ * Set of all field ids used in static field writes.
*/
- public final Set<DexField> staticFieldsWritten;
+ public final Set<DexField> staticFieldWrites;
/**
* Set of all methods referenced in virtual invokes;
*/
@@ -1042,12 +1067,12 @@
this.targetedMethods = toDescriptorSet(enqueuer.targetedMethods.getItems());
this.liveMethods = toDescriptorSet(enqueuer.liveMethods.getItems());
this.liveFields = toDescriptorSet(enqueuer.liveFields.getItems());
- this.instanceFieldsRead = enqueuer.collectInstanceFieldsRead();
- this.instanceFieldsWritten = enqueuer.collectInstanceFieldsWritten();
- this.staticFieldsRead = enqueuer.collectStaticFieldsRead();
- this.staticFieldsWritten = enqueuer.collectStaticFieldsWritten();
- this.fieldsRead = Sets.union(staticFieldsRead, instanceFieldsRead);
- this.fieldsWritten = Sets.union(staticFieldsWritten, instanceFieldsWritten);
+ this.instanceFieldReads = enqueuer.collectInstanceFieldsRead();
+ this.instanceFieldWrites = enqueuer.collectInstanceFieldsWritten();
+ this.staticFieldReads = enqueuer.collectStaticFieldsRead();
+ this.staticFieldWrites = enqueuer.collectStaticFieldsWritten();
+ this.fieldsRead = enqueuer.collectFieldsRead();
+ this.fieldsWritten = enqueuer.collectFieldsWritten();
this.pinnedItems = Collections.unmodifiableSet(enqueuer.pinnedItems);
this.virtualInvokes = joinInvokedMethods(enqueuer.virtualInvokes);
this.superInvokes = joinInvokedMethods(enqueuer.superInvokes);
@@ -1055,8 +1080,8 @@
this.staticInvokes = joinInvokedMethods(enqueuer.staticInvokes);
this.noSideEffects = enqueuer.rootSet.noSideEffects;
this.assumedValues = enqueuer.rootSet.assumedValues;
- assert Sets.intersection(instanceFieldsRead, staticFieldsRead).size() == 0;
- assert Sets.intersection(instanceFieldsWritten, staticFieldsWritten).size() == 0;
+ assert Sets.intersection(instanceFieldReads, staticFieldReads).size() == 0;
+ assert Sets.intersection(instanceFieldWrites, staticFieldWrites).size() == 0;
}
private AppInfoWithLiveness(AppInfoWithLiveness previous, DexApplication application) {
@@ -1066,11 +1091,12 @@
this.targetedMethods = previous.targetedMethods;
this.liveMethods = previous.liveMethods;
this.liveFields = previous.liveFields;
- this.instanceFieldsRead = previous.instanceFieldsRead;
- this.instanceFieldsWritten = previous.instanceFieldsWritten;
- this.staticFieldsRead = previous.staticFieldsRead;
- this.staticFieldsWritten = previous.staticFieldsWritten;
+ this.instanceFieldReads = previous.instanceFieldReads;
+ this.instanceFieldWrites = previous.instanceFieldWrites;
+ this.staticFieldReads = previous.staticFieldReads;
+ this.staticFieldWrites = previous.staticFieldWrites;
this.fieldsRead = previous.fieldsRead;
+ // TODO(herhut): We remove fields that are only written, so maybe update this.
this.fieldsWritten = previous.fieldsWritten;
this.pinnedItems = previous.pinnedItems;
this.noSideEffects = previous.noSideEffects;
@@ -1079,8 +1105,8 @@
this.superInvokes = previous.superInvokes;
this.directInvokes = previous.directInvokes;
this.staticInvokes = previous.staticInvokes;
- assert Sets.intersection(instanceFieldsRead, staticFieldsRead).size() == 0;
- assert Sets.intersection(instanceFieldsWritten, staticFieldsWritten).size() == 0;
+ assert Sets.intersection(instanceFieldReads, staticFieldReads).size() == 0;
+ assert Sets.intersection(instanceFieldWrites, staticFieldWrites).size() == 0;
}
private AppInfoWithLiveness(AppInfoWithLiveness previous, GraphLense lense) {
@@ -1090,12 +1116,12 @@
this.targetedMethods = rewriteItems(previous.targetedMethods, lense::lookupMethod);
this.liveMethods = rewriteItems(previous.liveMethods, lense::lookupMethod);
this.liveFields = rewriteItems(previous.liveFields, lense::lookupField);
- this.instanceFieldsRead = rewriteItems(previous.instanceFieldsRead, lense::lookupField);
- this.instanceFieldsWritten = rewriteItems(previous.instanceFieldsWritten, lense::lookupField);
- this.staticFieldsRead = rewriteItems(previous.staticFieldsRead, lense::lookupField);
- this.staticFieldsWritten = rewriteItems(previous.staticFieldsWritten, lense::lookupField);
- this.fieldsRead = Sets.union(staticFieldsRead, instanceFieldsRead);
- this.fieldsWritten = Sets.union(staticFieldsWritten, instanceFieldsWritten);
+ this.instanceFieldReads = rewriteItems(previous.instanceFieldReads, lense::lookupField);
+ this.instanceFieldWrites = rewriteItems(previous.instanceFieldWrites, lense::lookupField);
+ this.staticFieldReads = rewriteItems(previous.staticFieldReads, lense::lookupField);
+ this.staticFieldWrites = rewriteItems(previous.staticFieldWrites, lense::lookupField);
+ this.fieldsRead = rewriteItems(previous.fieldsRead, lense::lookupField);
+ this.fieldsWritten = rewriteItems(previous.fieldsWritten, lense::lookupField);
// TODO(herhut): Migrate these to Descriptors, as well.
this.pinnedItems = previous.pinnedItems;
this.noSideEffects = previous.noSideEffects;
@@ -1104,8 +1130,8 @@
this.superInvokes = rewriteItems(previous.superInvokes, lense::lookupMethod);
this.directInvokes = rewriteItems(previous.directInvokes, lense::lookupMethod);
this.staticInvokes = rewriteItems(previous.staticInvokes, lense::lookupMethod);
- assert Sets.intersection(instanceFieldsRead, staticFieldsRead).size() == 0;
- assert Sets.intersection(instanceFieldsWritten, staticFieldsWritten).size() == 0;
+ assert Sets.intersection(instanceFieldReads, staticFieldReads).size() == 0;
+ assert Sets.intersection(instanceFieldWrites, staticFieldWrites).size() == 0;
}
private Set<DexMethod> joinInvokedMethods(Map<DexType, Set<DexMethod>> invokes) {
diff --git a/src/test/examples/memberrebinding/Test.java b/src/test/examples/memberrebinding/Memberrebinding.java
similarity index 97%
rename from src/test/examples/memberrebinding/Test.java
rename to src/test/examples/memberrebinding/Memberrebinding.java
index 62a2440..74c99fd 100644
--- a/src/test/examples/memberrebinding/Test.java
+++ b/src/test/examples/memberrebinding/Memberrebinding.java
@@ -6,7 +6,7 @@
import memberrebinding.subpackage.PublicClass;
import memberrebindinglib.AnIndependentInterface;
-public class Test {
+public class Memberrebinding {
public static void main(String[] args) {
ClassAtBottomOfChain bottomInstance = new ClassAtBottomOfChain();
diff --git a/src/test/examples/memberrebinding2/Test.java b/src/test/examples/memberrebinding2/Memberrebinding.java
similarity index 96%
rename from src/test/examples/memberrebinding2/Test.java
rename to src/test/examples/memberrebinding2/Memberrebinding.java
index d4b005e..13cde8c 100644
--- a/src/test/examples/memberrebinding2/Test.java
+++ b/src/test/examples/memberrebinding2/Memberrebinding.java
@@ -5,7 +5,7 @@
import memberrebinding2.subpackage.PublicClass;
-public class Test {
+public class Memberrebinding {
public static void main(String[] args) {
ClassAtBottomOfChain bottomInstance = new ClassAtBottomOfChain();
diff --git a/src/test/examples/memberrebinding2/keep-rules.txt b/src/test/examples/memberrebinding2/keep-rules.txt
new file mode 100644
index 0000000..ae40c43
--- /dev/null
+++ b/src/test/examples/memberrebinding2/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2016, 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.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class memberrebinding2.Memberrebinding {
+ public static void main(...);
+}
+
+# Remove once b/62048823 is fixed.
+-allowaccessmodification
\ No newline at end of file
diff --git a/src/test/examples/memberrebinding3/Test.java b/src/test/examples/memberrebinding3/Memberrebinding.java
similarity index 78%
rename from src/test/examples/memberrebinding3/Test.java
rename to src/test/examples/memberrebinding3/Memberrebinding.java
index d37f263..83d8bbb 100644
--- a/src/test/examples/memberrebinding3/Test.java
+++ b/src/test/examples/memberrebinding3/Memberrebinding.java
@@ -3,16 +3,19 @@
// BSD-style license that can be found in the LICENSE file.
package memberrebinding3;
-public class Test extends ClassAtBottomOfChain {
+public class Memberrebinding extends ClassAtBottomOfChain {
+ @Override
void bottomMethod() {
}
+ @Override
void middleMethod() {
}
+ @Override
void topMethod() {
}
@@ -24,6 +27,6 @@
}
public static void main(String[] args) {
- new Test().test();
+ new Memberrebinding().test();
}
}
diff --git a/src/test/examplesAndroidN/memberrebinding4/Test.java b/src/test/examplesAndroidN/memberrebinding4/Memberrebinding.java
similarity index 93%
rename from src/test/examplesAndroidN/memberrebinding4/Test.java
rename to src/test/examplesAndroidN/memberrebinding4/Memberrebinding.java
index 6fc2ad5..a699537 100644
--- a/src/test/examplesAndroidN/memberrebinding4/Test.java
+++ b/src/test/examplesAndroidN/memberrebinding4/Memberrebinding.java
@@ -5,7 +5,7 @@
import memberrebinding4.subpackage.PublicInterface;
-public class Test {
+public class Memberrebinding {
static class Inner implements PublicInterface {
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index a264f48..9be6930 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -103,8 +103,8 @@
"regress_37875803.Regress",
"regress_37955340.Regress",
"regress_62300145.Regress",
- "memberrebinding2.Test",
- "memberrebinding3.Test",
+ "memberrebinding2.Memberrebinding",
+ "memberrebinding3.Memberrebinding",
"minification.Minification",
"enclosingmethod.Main",
"interfaceinlining.Main",
@@ -123,7 +123,7 @@
private static String[] makeTest(
DexTool tool, CompilerUnderTest compiler, CompilationMode mode, String clazz) {
String pkg = clazz.substring(0, clazz.lastIndexOf('.'));
- return new String[] {pkg, tool.name(), compiler.name(), mode.name(), clazz};
+ return new String[]{pkg, tool.name(), compiler.name(), mode.name(), clazz};
}
@Rule
diff --git a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
index 26067c7..376577c 100644
--- a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
+++ b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
@@ -25,7 +25,7 @@
private static final String EXAMPLE_DIR = ToolHelper.EXAMPLES_BUILD_DIR;
private static final String EXAMPLE_DEX = "memberrebinding/classes.dex";
private static final String EXAMPLE_LIB = "memberrebindinglib/classes.dex";
- private static final String EXAMPLE_CLASS = "memberrebinding.Test";
+ private static final String EXAMPLE_CLASS = "memberrebinding.Memberrebinding";
private static final String EXAMPLE_PACKAGE_MAP = "memberrebinding/package.map";
private static final String EXAMPLE_PROGUARD_MAP = "memberrebinding/proguard.map";
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
index 55bd373..c617c25 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
@@ -105,7 +105,8 @@
}
private static void inspectOriginalMain(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding.Test").method(DexInspector.MAIN);
+ MethodSubject main = inspector.clazz("memberrebinding.Memberrebinding")
+ .method(DexInspector.MAIN);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(MemberRebindingTest::coolInvokes);
assertTrue(iterator.next().holder().is("memberrebinding.ClassAtBottomOfChain"));
@@ -132,7 +133,8 @@
}
private static void inspectMain(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding.Test").method(DexInspector.MAIN);
+ MethodSubject main = inspector.clazz("memberrebinding.Memberrebinding")
+ .method(DexInspector.MAIN);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(MemberRebindingTest::coolInvokes);
assertTrue(iterator.next().holder().is("memberrebinding.ClassAtBottomOfChain"));
@@ -162,7 +164,8 @@
}
private static void inspectOriginalMain2(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding2.Test").method(DexInspector.MAIN);
+ MethodSubject main = inspector.clazz("memberrebinding2.Memberrebinding")
+ .method(DexInspector.MAIN);
Iterator<FieldAccessInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isFieldAccess);
// Run through instance put, static put, instance get and instance get.
@@ -177,7 +180,8 @@
}
private static void inspectMain2(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding2.Test").method(DexInspector.MAIN);
+ MethodSubject main = inspector.clazz("memberrebinding2.Memberrebinding")
+ .method(DexInspector.MAIN);
Iterator<FieldAccessInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isFieldAccess);
// Run through instance put, static put, instance get and instance get.
@@ -185,7 +189,7 @@
assertTrue(iterator.next().holder().is("memberrebinding2.ClassAtBottomOfChain"));
assertTrue(iterator.next().holder().is("memberrebinding2.ClassInMiddleOfChain"));
assertTrue(iterator.next().holder().is("memberrebinding2.SuperClassOfAll"));
- assertTrue(iterator.next().holder().is("memberrebinding2.subpackage.PackagePrivateClass"));
+ assertTrue(iterator.next().holder().is("memberrebinding2.subpackage.PublicClass"));
}
assertTrue(iterator.next().holder().is("java.lang.System"));
assertFalse(iterator.hasNext());
@@ -195,7 +199,7 @@
new MethodSignature("test", "void", new String[]{});
private static void inspectOriginal3(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding3.Test").method(TEST);
+ MethodSubject main = inspector.clazz("memberrebinding3.Memberrebinding").method(TEST);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isInvoke);
assertTrue(iterator.next().holder().is("memberrebinding3.ClassAtBottomOfChain"));
@@ -205,7 +209,7 @@
}
private static void inspect3(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding3.Test").method(TEST);
+ MethodSubject main = inspector.clazz("memberrebinding3.Memberrebinding").method(TEST);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isInvoke);
assertTrue(iterator.next().holder().is("memberrebinding3.ClassAtBottomOfChain"));
@@ -215,19 +219,19 @@
}
private static void inspectOriginal4(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding4.Test").method(TEST);
+ MethodSubject main = inspector.clazz("memberrebinding4.Memberrebinding").method(TEST);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isInvoke);
- assertTrue(iterator.next().holder().is("memberrebinding4.Test$Inner"));
+ assertTrue(iterator.next().holder().is("memberrebinding4.Memberrebinding$Inner"));
assertTrue(iterator.next().holder().is("memberrebinding4.subpackage.PublicInterface"));
assertFalse(iterator.hasNext());
}
private static void inspect4(DexInspector inspector) {
- MethodSubject main = inspector.clazz("memberrebinding4.Test").method(TEST);
+ MethodSubject main = inspector.clazz("memberrebinding4.Memberrebinding").method(TEST);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isInvoke);
- assertTrue(iterator.next().holder().is("memberrebinding4.Test$Inner"));
+ assertTrue(iterator.next().holder().is("memberrebinding4.Memberrebinding$Inner"));
assertTrue(iterator.next().holder().is("memberrebinding4.subpackage.PublicInterface"));
assertFalse(iterator.hasNext());
}
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
index 4530e2e..6a8cfb8 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -542,7 +542,9 @@
"assumevalues3",
"assumevalues4",
"assumevalues5",
- "annotationremoval");
+ "annotationremoval",
+ "memberrebinding2",
+ "memberrebinding3");
// Keys can be the name of the test or the name of the test followed by a colon and the name
// of the keep file.