Resolve misc. issues in repackaging
Bug: 165783399
Change-Id: I03f46a22129dead0a492e15a0ef8524cc82e894e
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 1605f20..500da1e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -415,13 +415,11 @@
public DexType replacePackage(String newPackageDescriptor, DexItemFactory dexItemFactory) {
assert isClassType();
String descriptorString = toDescriptorString();
- int lastPackageSeparator = descriptorString.lastIndexOf('/');
- String newDescriptorString = "L" + newPackageDescriptor + "/";
- if (lastPackageSeparator >= 0) {
- newDescriptorString += descriptorString.substring(lastPackageSeparator + 1);
- } else {
- newDescriptorString += descriptorString.substring(1);
+ String newDescriptorString = "L";
+ if (!newPackageDescriptor.isEmpty()) {
+ newDescriptorString += newPackageDescriptor + "/";
}
+ newDescriptorString += DescriptorUtils.getSimpleClassNameFromDescriptor(descriptorString) + ";";
return dexItemFactory.createType(newDescriptorString);
}
diff --git a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
index 74f9880..cd3baa0 100644
--- a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import java.util.function.Consumer;
import org.objectweb.asm.ClassWriter;
/** Representation of an entry in the Java InnerClasses attribute table. */
@@ -38,6 +39,15 @@
this.innerName = innerName;
}
+ public void forEachType(Consumer<DexType> consumer) {
+ if (inner != null) {
+ consumer.accept(inner);
+ }
+ if (outer != null) {
+ consumer.accept(outer);
+ }
+ }
+
public boolean isNamed() {
return innerName != null;
}
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 7f7ae1e..5868aa8 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -139,7 +139,7 @@
// Always repackage outer classes first, if any.
InnerClassAttribute innerClassAttribute = classToRepackage.getInnerClassAttributeForThisClass();
DexProgramClass outerClass = null;
- if (innerClassAttribute != null) {
+ if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
outerClass = asProgramClassOrNull(appView.definitionFor(innerClassAttribute.getOuter()));
if (outerClass != null) {
if (pkg.contains(outerClass)) {
@@ -171,7 +171,10 @@
if (proguardConfiguration.getPackageObfuscationMode().isRepackageClasses()) {
return newPackageDescriptor;
}
- newPackageDescriptor += "/" + pkg.getLastPackageName();
+ if (!newPackageDescriptor.isEmpty()) {
+ newPackageDescriptor += "/";
+ }
+ newPackageDescriptor += pkg.getLastPackageName();
String finalPackageDescriptor = newPackageDescriptor;
for (int i = 1; seenPackageDescriptors.contains(finalPackageDescriptor); i++) {
finalPackageDescriptor = newPackageDescriptor + INNER_CLASS_SEPARATOR + i;
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 5152bef..b50015b 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
@@ -110,19 +110,12 @@
}
// Trace the references to the inner and outer classes.
- clazz
- .getInnerClasses()
- .forEach(
- innerClassAttribute -> {
- registry.registerNullableTypeReference(innerClassAttribute.getInner());
- registry.registerNullableTypeReference(innerClassAttribute.getOuter());
- });
+ clazz.getInnerClasses().forEach(registry::registerInnerClassAttribute);
// Trace the references from the enclosing method attribute.
EnclosingMethodAttribute attr = clazz.getEnclosingMethodAttribute();
if (attr != null) {
- registry.registerNullableTypeReference(attr.getEnclosingClass());
- registry.registerNullableMethodReference(attr.getEnclosingMethod());
+ registry.registerEnclosingMethodAttribute(attr);
}
}
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
index 3591ff7..f519f01 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
@@ -154,9 +154,9 @@
List<InnerClassAttribute> newInnerClassAttributes = new ArrayList<>();
for (InnerClassAttribute innerClassAttribute : innerClassAttributes) {
DexType innerClassType = innerClassAttribute.getInner();
- DexType newInnerClassType = fixupType(innerClassType);
+ DexType newInnerClassType = fixupTypeOrNull(innerClassType);
DexType outerClassType = innerClassAttribute.getOuter();
- DexType newOuterClassType = fixupType(outerClassType);
+ DexType newOuterClassType = fixupTypeOrNull(outerClassType);
newInnerClassAttributes.add(
new InnerClassAttribute(
innerClassAttribute.getAccess(),
@@ -247,6 +247,10 @@
return changed ? newSynthesizedFrom : synthesizedFrom;
}
+ private DexType fixupTypeOrNull(DexType type) {
+ return type != null ? fixupType(type) : null;
+ }
+
private DexType fixupType(DexType type) {
if (type.isArrayType()) {
DexType base = type.toBaseType(dexItemFactory);
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 72810b0..b27182d 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.repackaging;
+import static com.google.common.base.Predicates.alwaysTrue;
+
import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassAccessFlags;
@@ -12,12 +14,18 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.EnclosingMethodAttribute;
+import com.android.tools.r8.graph.InnerClassAttribute;
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.ResolutionResult;
import com.android.tools.r8.graph.SuccessfulMemberResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
public class RepackagingUseRegistry extends UseRegistry {
@@ -65,14 +73,12 @@
registerMemberAccess(appInfo.resolveField(field));
}
- public void registerMethodReference(DexMethod method) {
- registerMemberAccess(appInfo.unsafeResolveMethodDueToDexFormat(method));
- }
-
- public void registerNullableMethodReference(DexMethod method) {
- if (method != null) {
- registerMethodReference(method);
- }
+ public ProgramMethod registerMethodReference(DexMethod method) {
+ ResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method);
+ registerMemberAccess(resolutionResult);
+ return resolutionResult.isSingleResolution()
+ ? resolutionResult.asSingleResolution().getResolvedProgramMethod()
+ : null;
}
public void registerMemberAccess(MemberResolutionResult<?, ?> resolutionResult) {
@@ -102,8 +108,12 @@
}
private void registerTypeAccess(DexType type) {
+ registerTypeAccess(type, this::registerTypeAccess);
+ }
+
+ private void registerTypeAccess(DexType type, Consumer<DexClass> consumer) {
if (type.isArrayType()) {
- registerTypeAccess(type.toBaseType(appInfo.dexItemFactory()));
+ registerTypeAccess(type.toBaseType(appInfo.dexItemFactory()), consumer);
return;
}
if (type.isPrimitiveType() || type.isVoidType()) {
@@ -112,18 +122,22 @@
assert type.isClassType();
DexClass clazz = appInfo.definitionFor(type);
if (clazz != null) {
- registerTypeAccess(clazz);
+ consumer.accept(clazz);
}
}
private void registerTypeAccess(DexClass clazz) {
+ registerTypeAccess(clazz, this::isOnlyAccessibleFromSamePackage);
+ }
+
+ private void registerTypeAccess(DexClass clazz, Predicate<DexProgramClass> predicate) {
// We only want to connect the current method node to the class node if the access requires the
// two nodes to be in the same package. Therefore, we ignore accesses to non-program classes
// and program classes outside the current package.
DexProgramClass programClass = clazz.asProgramClass();
if (programClass != null) {
RepackagingConstraintGraph.Node classNode = constraintGraph.getNode(programClass);
- if (classNode != null && isOnlyAccessibleFromSamePackage(programClass)) {
+ if (classNode != null && predicate.test(programClass)) {
node.addNeighbor(classNode);
}
}
@@ -189,14 +203,33 @@
registerTypeAccess(type);
}
- public void registerNullableTypeReference(DexType type) {
- if (type != null) {
- registerTypeReference(type);
- }
- }
-
@Override
public void registerInstanceOf(DexType type) {
registerTypeAccess(type);
}
+
+ public void registerEnclosingMethodAttribute(EnclosingMethodAttribute enclosingMethodAttribute) {
+ // For references in enclosing method attributes we add an edge from the context to the
+ // referenced item even if the item would be accessible from another package, to make sure that
+ // we don't split such classes into different packages.
+ if (enclosingMethodAttribute.getEnclosingClass() != null) {
+ registerTypeAccess(
+ enclosingMethodAttribute.getEnclosingClass(),
+ clazz -> registerTypeAccess(clazz, alwaysTrue()));
+ }
+ if (enclosingMethodAttribute.getEnclosingMethod() != null) {
+ ProgramMethod method = registerMethodReference(enclosingMethodAttribute.getEnclosingMethod());
+ if (method != null) {
+ registerTypeAccess(method.getHolder(), alwaysTrue());
+ }
+ }
+ }
+
+ public void registerInnerClassAttribute(InnerClassAttribute innerClassAttribute) {
+ // For references in inner class attributes we add an edge from the context to the referenced
+ // class even if the referenced class would be accessible from another package, to make sure
+ // that we don't split such classes into different packages.
+ innerClassAttribute.forEachType(
+ type -> registerTypeAccess(type, clazz -> registerTypeAccess(clazz, alwaysTrue())));
+ }
}