Resolve remaining tracing TODOs in repackaging
Bug: 165783399
Change-Id: Idc06584aa8143019f4e40d3bd2cdcd3715f47336
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index e3bf2d8..cde4638 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -562,7 +562,11 @@
}
public DexType getType() {
- return this.type;
+ return type;
+ }
+
+ public DexType getSuperType() {
+ return superType;
}
public boolean hasClassInitializer() {
@@ -817,6 +821,11 @@
return null;
}
+ public void forEachNestMember(Consumer<DexType> consumer) {
+ assert isNestHost();
+ getNestMembersClassAttributes().forEach(member -> consumer.accept(member.getNestMember()));
+ }
+
public NestHostClassAttribute getNestHostClassAttribute() {
return nestHost;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
index 7b11467..288b336 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
@@ -4,21 +4,11 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.origin.Origin;
-
-public class DexClassAndField {
-
- private final DexClass holder;
- private final DexEncodedField field;
+public class DexClassAndField extends DexClassAndMember<DexEncodedField, DexField> {
DexClassAndField(DexClass holder, DexEncodedField field) {
- assert holder != null;
- assert field != null;
- assert holder.type == field.holder();
+ super(holder, field);
assert holder.isProgramClass() == (this instanceof ProgramField);
- this.holder = holder;
- this.field = field;
}
public static DexClassAndField create(DexClass holder, DexEncodedField field) {
@@ -29,26 +19,6 @@
}
}
- public DexClass getHolder() {
- return holder;
- }
-
- public DexType getHolderType() {
- return holder.type;
- }
-
- public DexEncodedField getDefinition() {
- return field;
- }
-
- public DexField getReference() {
- return field.field;
- }
-
- public Origin getOrigin() {
- return holder.origin;
- }
-
public boolean isProgramField() {
return false;
}
@@ -56,23 +26,4 @@
public ProgramField asProgramField() {
return null;
}
-
- public String toSourceString() {
- return getReference().toSourceString();
- }
-
- @Override
- public String toString() {
- return toSourceString();
- }
-
- @Override
- public boolean equals(Object object) {
- throw new Unreachable("Unsupported attempt at comparing Class and DexClassAndField");
- }
-
- @Override
- public int hashCode() {
- throw new Unreachable("Unsupported attempt at computing the hashcode of DexClassAndField");
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
new file mode 100644
index 0000000..0bc5348
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
@@ -0,0 +1,66 @@
+// Copyright (c) 2020, 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.graph;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.origin.Origin;
+
+public abstract class DexClassAndMember<
+ D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> {
+
+ private final DexClass holder;
+ private final D definition;
+
+ public DexClassAndMember(DexClass holder, D definition) {
+ assert holder != null;
+ assert definition != null;
+ assert holder.type == definition.holder();
+ this.holder = holder;
+ this.definition = definition;
+ }
+
+ public DexType getContextType() {
+ return getHolderType();
+ }
+
+ public DexClass getHolder() {
+ return holder;
+ }
+
+ public DexType getHolderType() {
+ return holder.type;
+ }
+
+ public D getDefinition() {
+ return definition;
+ }
+
+ public R getReference() {
+ return definition.toReference();
+ }
+
+ public Origin getOrigin() {
+ return holder.origin;
+ }
+
+ public String toSourceString() {
+ return getReference().toSourceString();
+ }
+
+ @Override
+ public String toString() {
+ return toSourceString();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ throw new Unreachable("Unsupported attempt at comparing Class and DexClassAndMember");
+ }
+
+ @Override
+ public int hashCode() {
+ throw new Unreachable("Unsupported attempt at computing the hash code of DexClassAndMember");
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index c6c2f07..87d1bb9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -4,21 +4,12 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.origin.Origin;
-
-public class DexClassAndMethod implements LookupTarget {
-
- private final DexClass holder;
- private final DexEncodedMethod method;
+public class DexClassAndMethod extends DexClassAndMember<DexEncodedMethod, DexMethod>
+ implements LookupTarget {
DexClassAndMethod(DexClass holder, DexEncodedMethod method) {
- assert holder != null;
- assert method != null;
- assert holder.type == method.holder();
+ super(holder, method);
assert holder.isProgramClass() == (this instanceof ProgramMethod);
- this.holder = holder;
- this.method = method;
}
public static DexClassAndMethod create(DexClass holder, DexEncodedMethod method) {
@@ -33,16 +24,6 @@
}
@Override
- public boolean equals(Object object) {
- throw new Unreachable("Unsupported attempt at comparing Class and DexClassAndMethod");
- }
-
- @Override
- public int hashCode() {
- throw new Unreachable("Unsupported attempt at computing the hashcode of DexClassAndMethod");
- }
-
- @Override
public boolean isMethodTarget() {
return true;
}
@@ -52,26 +33,6 @@
return this;
}
- public DexClass getHolder() {
- return holder;
- }
-
- public DexType getHolderType() {
- return holder.type;
- }
-
- public DexEncodedMethod getDefinition() {
- return method;
- }
-
- public DexMethod getReference() {
- return method.method;
- }
-
- public Origin getOrigin() {
- return holder.origin;
- }
-
public boolean isClasspathMethod() {
return false;
}
@@ -87,13 +48,4 @@
public ProgramMethod asProgramMethod() {
return null;
}
-
- public String toSourceString() {
- return method.method.toSourceString();
- }
-
- @Override
- public String toString() {
- return toSourceString();
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
index e480799..cb4eb4e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.utils.ArrayUtils;
import java.util.Arrays;
+import java.util.function.Consumer;
import java.util.function.Function;
public class DexEncodedAnnotation extends DexItem {
@@ -30,6 +31,12 @@
}
}
+ public void forEachElement(Consumer<DexAnnotationElement> consumer) {
+ for (DexAnnotationElement element : elements) {
+ consumer.accept(element);
+ }
+ }
+
public DexAnnotationElement getElement(int i) {
return elements[i];
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 31903d7..4936ceb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -775,6 +775,10 @@
return builder.toString();
}
+ public ParameterAnnotationsList getParameterAnnotations() {
+ return parameterAnnotationsList;
+ }
+
public void clearParameterAnnotations() {
parameterAnnotationsList = ParameterAnnotationsList.empty();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index a58ec39..0997619 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -23,6 +23,10 @@
}
}
+ public DexType getType() {
+ return type;
+ }
+
@Override
public DexEncodedField lookupOnClass(DexClass clazz) {
return clazz != null ? clazz.lookupField(this) : null;
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index c2caa61..15e75bf 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -29,6 +29,10 @@
}
}
+ public DexType getHolderType() {
+ return holder;
+ }
+
public DexString getName() {
return name;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index f0efe20..ca7a264 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -29,7 +29,8 @@
import java.util.function.Predicate;
import java.util.function.Supplier;
-public class DexProgramClass extends DexClass implements Supplier<DexProgramClass> {
+public class DexProgramClass extends DexClass
+ implements ProgramDefinition, Supplier<DexProgramClass> {
@FunctionalInterface
public interface ChecksumSupplier {
@@ -491,6 +492,16 @@
return this;
}
+ @Override
+ public DexType getContextType() {
+ return getType();
+ }
+
+ @Override
+ public DexProgramClass getDefinition() {
+ return this;
+ }
+
public void setInitialClassFileVersion(int initialClassFileVersion) {
assert this.initialClassFileVersion == -1 && initialClassFileVersion > 0;
this.initialClassFileVersion = initialClassFileVersion;
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java
index 09985c3..a0cacd9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProto.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.naming.NamingLens;
import com.google.common.hash.Hasher;
+import java.util.function.Consumer;
public class DexProto extends IndexedDexItem implements PresortedComparable<DexProto> {
@@ -21,6 +22,11 @@
this.parameters = parameters;
}
+ public void forEachType(Consumer<DexType> consumer) {
+ consumer.accept(returnType);
+ parameters.forEach(consumer);
+ }
+
public DexType getParameter(int index) {
return parameters.values[index];
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index c61de91..ae25597 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.ArrayUtils;
import java.util.Arrays;
+import java.util.function.Consumer;
import java.util.stream.Stream;
public class DexTypeList extends DexItem {
@@ -34,6 +35,12 @@
return ArrayUtils.contains(values, type);
}
+ public void forEach(Consumer<DexType> consumer) {
+ for (DexType value : values) {
+ consumer.accept(value);
+ }
+ }
+
@Override
public int hashCode() {
return Arrays.hashCode(values);
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index 2fe8c3f..273c69a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.EncodedValueUtils;
import java.util.Arrays;
+import java.util.function.Consumer;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Type;
@@ -1381,6 +1382,12 @@
this.values = values;
}
+ public void forEachElement(Consumer<DexValue> consumer) {
+ for (DexValue value : values) {
+ consumer.accept(value);
+ }
+ }
+
public DexValue[] getValues() {
return values;
}
@@ -1474,6 +1481,10 @@
this.value = value;
}
+ public DexEncodedAnnotation getValue() {
+ return value;
+ }
+
@Override
public DexValueKind getValueKind() {
return DexValueKind.ANNOTATION;
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
new file mode 100644
index 0000000..91edb06
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, 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.graph;
+
+public interface ProgramDefinition {
+
+ DexType getContextType();
+
+ DexDefinition getDefinition();
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMember.java b/src/main/java/com/android/tools/r8/graph/ProgramMember.java
index 7dc209c..328c71f 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMember.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMember.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.graph;
-public interface ProgramMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> {
+public interface ProgramMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
+ extends ProgramDefinition {
+ @Override
D getDefinition();
DexType getHolderType();
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingAnnotationTracer.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingAnnotationTracer.java
new file mode 100644
index 0000000..f52b8b7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingAnnotationTracer.java
@@ -0,0 +1,108 @@
+// Copyright (c) 2020, 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.repackaging;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotationElement;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
+import com.android.tools.r8.graph.DexMethodHandle;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+
+public class RepackagingAnnotationTracer {
+
+ private final AppInfoWithClassHierarchy appInfo;
+ private final RepackagingUseRegistry registry;
+
+ public RepackagingAnnotationTracer(
+ AppView<? extends AppInfoWithClassHierarchy> appView, RepackagingUseRegistry registry) {
+ this.appInfo = appView.appInfo();
+ this.registry = registry;
+ }
+
+ public void trace(DexAnnotationSet annotations) {
+ annotations.forEach(this::traceAnnotation);
+ }
+
+ public void trace(ParameterAnnotationsList annotations) {
+ annotations.forEachAnnotation(this::traceAnnotation);
+ }
+
+ private void traceAnnotation(DexAnnotation annotation) {
+ traceEncodedAnnotation(annotation.annotation);
+ }
+
+ private void traceEncodedAnnotation(DexEncodedAnnotation annotation) {
+ registry.registerTypeReference(annotation.type);
+ annotation.forEachElement(this::traceAnnotationElement);
+ }
+
+ private void traceAnnotationElement(DexAnnotationElement element) {
+ traceDexValue(element.value);
+ }
+
+ private void traceDexValue(DexValue value) {
+ switch (value.getValueKind()) {
+ case BOOLEAN:
+ case BYTE:
+ case CHAR:
+ case DOUBLE:
+ case FLOAT:
+ case INT:
+ case LONG:
+ case NULL:
+ case SHORT:
+ case STRING:
+ break;
+
+ case ANNOTATION:
+ traceEncodedAnnotation(value.asDexValueAnnotation().getValue());
+ break;
+
+ case ARRAY:
+ value.asDexValueArray().forEachElement(this::traceDexValue);
+ break;
+
+ case ENUM:
+ registry.registerFieldAccess(value.asDexValueEnum().getValue());
+ break;
+
+ case FIELD:
+ registry.registerFieldAccess(value.asDexValueField().getValue());
+ break;
+
+ case METHOD:
+ registry.registerMethodReference(value.asDexValueMethod().getValue());
+ break;
+
+ case METHOD_HANDLE:
+ {
+ DexMethodHandle handle = value.asDexValueMethodHandle().getValue();
+ if (handle.isFieldHandle()) {
+ registry.registerFieldAccess(handle.asField());
+ } else {
+ assert handle.isMethodHandle();
+ registry.registerMethodReference(handle.asMethod());
+ }
+ }
+ break;
+
+ case METHOD_TYPE:
+ value.asDexValueMethodType().getValue().forEachType(registry::registerTypeReference);
+ break;
+
+ case TYPE:
+ registry.registerTypeReference(value.asDexValueType().getValue());
+ break;
+
+ default:
+ throw new Unreachable();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
index 33bbc11..1d97079 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ProgramPackage;
@@ -68,7 +69,7 @@
}
private Node createNode(DexDefinition definition) {
- Node node = new Node(definition);
+ Node node = new Node();
nodes.put(definition, node);
return node;
}
@@ -89,23 +90,65 @@
}
private void registerReferencesFromClass(DexProgramClass clazz) {
- // TODO(b/165783399): Trace the references to the immediate super types.
- // TODO(b/165783399): Maybe trace the references in the nest host and/or members.
- // TODO(b/165783399): Maybe trace the references to the inner classes.
- // TODO(b/165783399): Maybe trace the references in @kotlin.Metadata.
+ RepackagingUseRegistry registry = new RepackagingUseRegistry(appView, this, clazz);
+
+ // Trace the references to the immediate super types.
+ registry.registerTypeReference(clazz.getSuperType());
+ clazz.interfaces.forEach(registry::registerTypeReference);
+
+ // Trace the references from the class annotations.
+ new RepackagingAnnotationTracer(appView, registry).trace(clazz.annotations());
+
+ // Trace the references in the nest host and/or members.
+ if (clazz.isInANest()) {
+ if (clazz.isNestHost()) {
+ clazz.forEachNestMember(registry::registerTypeReference);
+ } else {
+ assert clazz.isNestMember();
+ registry.registerTypeReference(clazz.getNestHost());
+ }
+ }
+
+ // Trace the references to the inner and outer classes.
+ clazz
+ .getInnerClasses()
+ .forEach(
+ innerClassAttribute -> {
+ registry.registerNullableTypeReference(innerClassAttribute.getInner());
+ registry.registerNullableTypeReference(innerClassAttribute.getOuter());
+ });
+
+ // Trace the references from the enclosing method attribute.
+ EnclosingMethodAttribute attr = clazz.getEnclosingMethodAttribute();
+ registry.registerNullableTypeReference(attr.getEnclosingClass());
+ registry.registerNullableMethodReference(attr.getEnclosingMethod());
}
private void registerReferencesFromField(ProgramField field) {
- // TODO(b/165783399): Trace the type of the field.
- // TODO(b/165783399): Trace the references in the field annotations.
+ RepackagingUseRegistry registry = new RepackagingUseRegistry(appView, this, field);
+
+ // Trace the type of the field.
+ registry.registerTypeReference(field.getReference().getType());
+
+ // Trace the references in the field annotations.
+ new RepackagingAnnotationTracer(appView, registry).trace(field.getDefinition().annotations());
}
private void registerReferencesFromMethod(ProgramMethod method) {
- // TODO(b/165783399): Trace the type references in the method signature.
- // TODO(b/165783399): Trace the references in the method and method parameter annotations.
DexEncodedMethod definition = method.getDefinition();
+ RepackagingUseRegistry registry = new RepackagingUseRegistry(appView, this, method);
+
+ // Trace the type references in the method signature.
+ definition.getProto().forEachType(registry::registerTypeReference);
+
+ // Trace the references in the method and method parameter annotations.
+ RepackagingAnnotationTracer annotationTracer =
+ new RepackagingAnnotationTracer(appView, registry);
+ annotationTracer.trace(definition.annotations());
+ annotationTracer.trace(definition.getParameterAnnotations());
+
+ // Trace the references from the code.
if (definition.hasCode()) {
- RepackagingUseRegistry registry = new RepackagingUseRegistry(appView, this, method);
definition.getCode().registerCodeReferences(method, registry);
}
}
@@ -127,14 +170,8 @@
static class Node {
- private final DexDefinition definition;
-
private final Set<Node> neighbors = Sets.newConcurrentHashSet();
- private Node(DexDefinition definition) {
- this.definition = definition;
- }
-
public void addNeighbor(Node neighbor) {
neighbors.add(neighbor);
neighbor.neighbors.add(this);
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
index 531e6c8..72810b0 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -13,8 +13,8 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MemberResolutionResult;
+import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMember;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.SuccessfulMemberResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -23,13 +23,13 @@
private final AppInfoWithLiveness appInfo;
private final RepackagingConstraintGraph constraintGraph;
- private final ProgramMethod context;
+ private final ProgramDefinition context;
private final RepackagingConstraintGraph.Node node;
public RepackagingUseRegistry(
AppView<AppInfoWithLiveness> appView,
RepackagingConstraintGraph constraintGraph,
- ProgramMethod context) {
+ ProgramDefinition context) {
super(appView.dexItemFactory());
this.appInfo = appView.appInfo();
this.constraintGraph = constraintGraph;
@@ -43,7 +43,7 @@
return true;
}
if (accessFlags.isProtected()
- && !appInfo.isSubtype(context.getHolderType(), referencedClass.getType())) {
+ && !appInfo.isSubtype(context.getContextType(), referencedClass.getType())) {
return true;
}
return false;
@@ -55,13 +55,27 @@
return true;
}
if (accessFlags.isProtected()
- && !appInfo.isSubtype(context.getHolderType(), member.getHolderType())) {
+ && !appInfo.isSubtype(context.getContextType(), member.getHolderType())) {
return true;
}
return false;
}
- private void registerMemberAccess(MemberResolutionResult<?, ?> resolutionResult) {
+ public void registerFieldAccess(DexField field) {
+ registerMemberAccess(appInfo.resolveField(field));
+ }
+
+ public void registerMethodReference(DexMethod method) {
+ registerMemberAccess(appInfo.unsafeResolveMethodDueToDexFormat(method));
+ }
+
+ public void registerNullableMethodReference(DexMethod method) {
+ if (method != null) {
+ registerMethodReference(method);
+ }
+ }
+
+ public void registerMemberAccess(MemberResolutionResult<?, ?> resolutionResult) {
SuccessfulMemberResolutionResult<?, ?> successfulResolutionResult =
resolutionResult.asSuccessfulMemberResolutionResult();
if (successfulResolutionResult == null) {
@@ -92,7 +106,7 @@
registerTypeAccess(type.toBaseType(appInfo.dexItemFactory()));
return;
}
- if (type.isPrimitiveType()) {
+ if (type.isPrimitiveType() || type.isVoidType()) {
return;
}
assert type.isClassType();
@@ -147,12 +161,12 @@
@Override
public void registerInstanceFieldRead(DexField field) {
- registerMemberAccess(appInfo.resolveField(field));
+ registerFieldAccess(field);
}
@Override
public void registerInstanceFieldWrite(DexField field) {
- registerMemberAccess(appInfo.resolveField(field));
+ registerFieldAccess(field);
}
@Override
@@ -162,12 +176,12 @@
@Override
public void registerStaticFieldRead(DexField field) {
- registerMemberAccess(appInfo.resolveField(field));
+ registerFieldAccess(field);
}
@Override
public void registerStaticFieldWrite(DexField field) {
- registerMemberAccess(appInfo.resolveField(field));
+ registerFieldAccess(field);
}
@Override
@@ -175,6 +189,12 @@
registerTypeAccess(type);
}
+ public void registerNullableTypeReference(DexType type) {
+ if (type != null) {
+ registerTypeReference(type);
+ }
+ }
+
@Override
public void registerInstanceOf(DexType type) {
registerTypeAccess(type);
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 98881e9..69a42a4 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -261,6 +261,11 @@
return addKeepRules("-keepattributes " + String.join(",", attributes));
}
+ public T addKeepAttributeInnerClassesAndEnclosingMethod() {
+ return addKeepAttributes(
+ ProguardKeepAttributes.INNER_CLASSES, ProguardKeepAttributes.ENCLOSING_METHOD);
+ }
+
public T addKeepAttributeLineNumberTable() {
return addKeepAttributes(ProguardKeepAttributes.LINE_NUMBER_TABLE);
}
@@ -273,6 +278,10 @@
return addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS);
}
+ public T addKeepRuntimeVisibleParameterAnnotations() {
+ return addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
+ }
+
public T addKeepAllAttributes() {
return addKeepAttributes("*");
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateClassAnnotationTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateClassAnnotationTest.java
new file mode 100644
index 0000000..811d2ac
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateClassAnnotationTest.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateClassAnnotationTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateClassAnnotationTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptAnnotation.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addKeepRuntimeVisibleAnnotations()
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet();
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE})
+ @interface NonPublicKeptAnnotation {}
+
+ @NonPublicKeptAnnotation
+ public static class IneligibleForRepackaging {
+
+ @NeverInline
+ public static void greet() {
+ System.out.println("Hello world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateFieldAnnotationTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateFieldAnnotationTest.java
new file mode 100644
index 0000000..cd3eb8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateFieldAnnotationTest.java
@@ -0,0 +1,104 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateFieldAnnotationTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateFieldAnnotationTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptAnnotation.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addKeepRuntimeVisibleAnnotations()
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .enableMemberValuePropagationAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet();
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.FIELD})
+ @interface NonPublicKeptAnnotation {}
+
+ public static class IneligibleForRepackaging {
+
+ @NeverPropagateValue @NonPublicKeptAnnotation private static String GREETING = "Hello world!";
+
+ @NeverInline
+ public static void greet() {
+ System.out.println(GREETING);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateFieldTypeTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateFieldTypeTest.java
new file mode 100644
index 0000000..7a83908
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateFieldTypeTest.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateFieldTypeTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateFieldTypeTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptClass.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet();
+ }
+ }
+
+ static class NonPublicKeptClass {}
+
+ public static class PublicSubClass extends NonPublicKeptClass {}
+
+ public static class IneligibleForRepackaging {
+
+ @NeverPropagateValue
+ private static NonPublicKeptClass FIELD =
+ System.currentTimeMillis() > 0 ? new PublicSubClass() : null;
+
+ @NeverInline
+ public static void greet() {
+ if (FIELD != null) {
+ System.out.println("Hello world!");
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateInnerClassTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateInnerClassTest.java
new file mode 100644
index 0000000..51f37b6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateInnerClassTest.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.repackage.RepackageWithPackagePrivateInnerClassTest.IneligibleForRepackaging.NonPublicKeptClass;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateInnerClassTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateInnerClassTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptClass.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addKeepAttributeInnerClassesAndEnclosingMethod()
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet();
+ }
+ }
+
+ public static class IneligibleForRepackaging {
+
+ @NeverInline
+ public static void greet() {
+ System.out.println("Hello world!");
+ }
+
+ static class NonPublicKeptClass {}
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateInterfaceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateInterfaceTest.java
new file mode 100644
index 0000000..01d3358
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateInterfaceTest.java
@@ -0,0 +1,93 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateInterfaceTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateInterfaceTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptInterface.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet();
+ }
+ }
+
+ interface NonPublicKeptInterface {}
+
+ public static class IneligibleForRepackaging implements NonPublicKeptInterface {
+
+ @NeverInline
+ public static void greet() {
+ System.out.println("Hello world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateMethodAnnotationTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateMethodAnnotationTest.java
new file mode 100644
index 0000000..535eb6b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateMethodAnnotationTest.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateMethodAnnotationTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateMethodAnnotationTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptAnnotation.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addKeepRuntimeVisibleAnnotations()
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet();
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD})
+ @interface NonPublicKeptAnnotation {}
+
+ public static class IneligibleForRepackaging {
+
+ @NonPublicKeptAnnotation
+ @NeverInline
+ public static void greet() {
+ System.out.println("Hello world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateMethodParameterAnnotationTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateMethodParameterAnnotationTest.java
new file mode 100644
index 0000000..ece0498
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateMethodParameterAnnotationTest.java
@@ -0,0 +1,100 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateMethodParameterAnnotationTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateMethodParameterAnnotationTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptAnnotation.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addKeepRuntimeVisibleParameterAnnotations()
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet("Hello world!");
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.PARAMETER})
+ @interface NonPublicKeptAnnotation {}
+
+ public static class IneligibleForRepackaging {
+
+ @NeverInline
+ public static void greet(@NonPublicKeptAnnotation String greeting) {
+ System.out.println(greeting);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateSuperClassTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateSuperClassTest.java
new file mode 100644
index 0000000..43c3361
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateSuperClassTest.java
@@ -0,0 +1,93 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithPackagePrivateSuperClassTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithPackagePrivateSuperClassTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassRules(NonPublicKeptClass.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(IneligibleForRepackaging.class);
+ assertThat(classSubject, isPresent());
+
+ // Verify that the class was not repackaged.
+ assertEquals(
+ IneligibleForRepackaging.class.getPackage().getName(),
+ classSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ IneligibleForRepackaging.greet();
+ }
+ }
+
+ static class NonPublicKeptClass {}
+
+ public static class IneligibleForRepackaging extends NonPublicKeptClass {
+
+ @NeverInline
+ public static void greet() {
+ System.out.println("Hello world!");
+ }
+ }
+}