[Compose] Add support for composing outline call sites
Bug: b/242682464
Change-Id: I476e64fbd2206763782a75b938ae2e380862503d
diff --git a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
index 6e1bc00..d99e801 100644
--- a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
+++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -11,14 +11,22 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.naming.mappinginformation.OutlineCallsiteMappingInformation;
+import com.android.tools.r8.naming.mappinginformation.OutlineMappingInformation;
import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation;
import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation.ThrowsCondition;
+import com.android.tools.r8.references.ArrayReference;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.BiMapContainer;
+import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.utils.ChainableStringConsumer;
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SegmentTree;
+import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2IntSortedMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import java.util.ArrayList;
@@ -28,48 +36,70 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
public class ComposingBuilder {
- /**
- * To ensure we can do alpha renaming of classes and members without polluting the existing
- * mappping, we use a committed map that we update for each class name mapping. That allows us to
- * rename to existing renamed names as long as these are also renamed later in the map.
- */
- private final Map<String, ComposingClassBuilder> committed = new HashMap<>();
-
- private Map<String, ComposingClassBuilder> current = new HashMap<>();
-
private MapVersionMappingInformation currentMapVersion = null;
- private final ComposingSharedData sharedData = new ComposingSharedData();
+ /**
+ * When composing we store a view of the previously known mappings in committed and retain a
+ * current working set. When composing of a new map is finished we commit everything in current
+ * into the committed set.
+ *
+ * <p>The reason for not having just a single set is that we can have a circular mapping as
+ * follows:
+ *
+ * <pre>
+ * a -> b:
+ * ...
+ * b -> a:
+ * </pre>
+ *
+ * After composing our current view of a with the above, we could end up transforming 'a' into 'b'
+ * and then later transforming 'b' back into 'a' again. To ensure we do not mess up namings while
+ * composing classes and methods we resort to a working set and committed set.
+ */
+ private final ComposingData committed = new ComposingData();
+
+ private ComposingData current;
public void compose(ClassNameMapper classNameMapper) throws MappingComposeException {
- MapVersionMappingInformation thisMapVersion = classNameMapper.getFirstMapVersionInformation();
- if (thisMapVersion != null) {
+ current = new ComposingData();
+ MapVersionMappingInformation newMapVersionInfo =
+ classNameMapper.getFirstMapVersionInformation();
+ if (newMapVersionInfo != null) {
+ MapVersion newMapVersion = newMapVersionInfo.getMapVersion();
+ if (newMapVersion.isLessThan(MapVersion.MAP_VERSION_2_1) || newMapVersion.isUnknown()) {
+ throw new MappingComposeException(
+ "Composition of mapping files supported from map version 2.1.");
+ }
if (currentMapVersion == null
- || currentMapVersion.getMapVersion().isLessThan(thisMapVersion.getMapVersion())) {
- currentMapVersion = thisMapVersion;
+ || currentMapVersion.getMapVersion().isLessThan(newMapVersion)) {
+ currentMapVersion = newMapVersionInfo;
}
}
- sharedData.patchupMappingInformation(classNameMapper);
for (ClassNamingForNameMapper classMapping : classNameMapper.getClassNameMappings().values()) {
compose(classMapping);
}
- commit();
+ committed.commit(current, classNameMapper);
}
private void compose(ClassNamingForNameMapper classMapping) throws MappingComposeException {
String originalName = classMapping.originalName;
- ComposingClassBuilder composingClassBuilder = committed.get(originalName);
+ ComposingClassBuilder composingClassBuilder = committed.classBuilders.get(originalName);
String renamedName = classMapping.renamedName;
if (composingClassBuilder == null) {
- composingClassBuilder = new ComposingClassBuilder(originalName, renamedName, sharedData);
+ composingClassBuilder = new ComposingClassBuilder(originalName, renamedName);
} else {
composingClassBuilder.setRenamedName(renamedName);
- committed.remove(originalName);
+ committed.classBuilders.remove(originalName);
}
- ComposingClassBuilder duplicateMapping = current.put(renamedName, composingClassBuilder);
+ composingClassBuilder.setCurrentComposingData(current, classMapping.originalName);
+ ComposingClassBuilder duplicateMapping =
+ current.classBuilders.put(renamedName, composingClassBuilder);
if (duplicateMapping != null) {
throw new MappingComposeException(
"Duplicate class mapping. Both '"
@@ -83,31 +113,13 @@
composingClassBuilder.compose(classMapping);
}
- private void commit() throws MappingComposeException {
- for (Entry<String, ComposingClassBuilder> newEntry : current.entrySet()) {
- String renamedName = newEntry.getKey();
- ComposingClassBuilder classBuilder = newEntry.getValue();
- ComposingClassBuilder duplicateMapping = committed.put(renamedName, classBuilder);
- if (duplicateMapping != null) {
- throw new MappingComposeException(
- "Duplicate class mapping. Both '"
- + duplicateMapping.getOriginalName()
- + "' and '"
- + classBuilder.getOriginalName()
- + "' maps to '"
- + renamedName
- + "'.");
- }
- }
- current = new HashMap<>();
- }
@Override
public String toString() {
- List<ComposingClassBuilder> classBuilders = new ArrayList<>(committed.values());
+ List<ComposingClassBuilder> classBuilders = new ArrayList<>(committed.classBuilders.values());
classBuilders.sort(Comparator.comparing(ComposingClassBuilder::getOriginalName));
StringBuilder sb = new StringBuilder();
- // TODO(b/241763080): Keep preamble of mapping files"
+ // TODO(b/241763080): Keep preamble of mapping files
if (currentMapVersion != null) {
sb.append("# ").append(currentMapVersion.serialize()).append("\n");
}
@@ -118,34 +130,243 @@
return sb.toString();
}
- public static class ComposingSharedData {
+ public static class ComposingData {
/**
+ * A map of minified names to their class builders. When committing to a new minified name we
+ * destructively remove the previous minified mapping and replace it with the up-to-date one.
+ */
+ private final Map<String, ComposingClassBuilder> classBuilders = new HashMap<>();
+ /**
* RewriteFrameInformation contains condition clauses that are bound to the residual program. As
* a result of that, we have to patch up the conditions when we compose new class mappings.
*/
- private final List<RewriteFrameMappingInformation> mappingInformationToPatchUp =
- new ArrayList<>();
+ private final List<RewriteFrameMappingInformation> rewriteFrameInformation = new ArrayList<>();
+ /** Map of newly added outline call site informations which do not require any rewriting. */
+ private Map<ClassDescriptorAndMethodName, OutlineCallsiteMappingInformation>
+ outlineCallsiteInformation = new HashMap<>();
+ /**
+ * Map of updated outline definitions which has to be committed. The positions in the caller are
+ * fixed at this point since these are local to the method when rewriting.
+ */
+ private final Map<ClassDescriptorAndMethodName, UpdateOutlineCallsiteInformation>
+ outlineSourcePositionsUpdated = new HashMap<>();
- private void patchupMappingInformation(ClassNameMapper classNameMapper) {
- BiMapContainer<String, String> obfuscatedToOriginalMapping =
- classNameMapper.getObfuscatedToOriginalMapping();
- for (RewriteFrameMappingInformation rewriteMappingInfo : mappingInformationToPatchUp) {
+ public void commit(ComposingData current, ClassNameMapper classNameMapper)
+ throws MappingComposeException {
+ commitClassBuilders(current);
+ commitRewriteFrameInformation(current, classNameMapper);
+ commitOutlineCallsiteInformation(current, classNameMapper);
+ }
+
+ private void commitClassBuilders(ComposingData current) throws MappingComposeException {
+ for (Entry<String, ComposingClassBuilder> newEntry : current.classBuilders.entrySet()) {
+ String renamedName = newEntry.getKey();
+ ComposingClassBuilder classBuilder = newEntry.getValue();
+ ComposingClassBuilder duplicateMapping = classBuilders.put(renamedName, classBuilder);
+ if (duplicateMapping != null) {
+ throw new MappingComposeException(
+ "Duplicate class mapping. Both '"
+ + duplicateMapping.getOriginalName()
+ + "' and '"
+ + classBuilder.getOriginalName()
+ + "' maps to '"
+ + renamedName
+ + "'.");
+ }
+ }
+ }
+
+ private void commitRewriteFrameInformation(
+ ComposingData current, ClassNameMapper classNameMapper) {
+ // First update the existing frame information to have new class name mappings.
+ Map<String, String> inverse = classNameMapper.getObfuscatedToOriginalMapping().inverse;
+ for (RewriteFrameMappingInformation rewriteMappingInfo : rewriteFrameInformation) {
rewriteMappingInfo
.getConditions()
.forEach(
rewriteCondition -> {
ThrowsCondition throwsCondition = rewriteCondition.asThrowsCondition();
if (throwsCondition != null) {
- String originalName = throwsCondition.getClassReference().getTypeName();
- String obfuscatedName = obfuscatedToOriginalMapping.inverse.get(originalName);
- if (obfuscatedName != null) {
- throwsCondition.setClassReferenceInternal(
- Reference.classFromTypeName(obfuscatedName));
- }
+ throwsCondition.setClassReferenceInternal(
+ mapTypeReference(inverse, throwsCondition.getClassReference()).asClass());
}
});
}
+ rewriteFrameInformation.addAll(current.rewriteFrameInformation);
+ }
+
+ private void commitOutlineCallsiteInformation(
+ ComposingData current, ClassNameMapper classNameMapper) {
+ // To commit outline call site information, we take the previously committed and bring forward
+ // to a new mapping, and potentially rewrite source positions if available.
+ Map<ClassDescriptorAndMethodName, OutlineCallsiteMappingInformation> newOutlineCallsiteInfo =
+ new HashMap<>();
+ Map<String, String> inverse = classNameMapper.getObfuscatedToOriginalMapping().inverse;
+ outlineCallsiteInformation.forEach(
+ (holderAndMethodNameOfOutline, outlineInfo) -> {
+ UpdateOutlineCallsiteInformation updateOutlineCallsiteInformation =
+ current.outlineSourcePositionsUpdated.get(holderAndMethodNameOfOutline);
+ String newMethodName = outlineInfo.getOutline().getMethodName();
+ if (updateOutlineCallsiteInformation != null) {
+ // We have a callsite mapping that we need to update.
+ MappedRangeOriginalToMinifiedMap originalToMinifiedMap =
+ MappedRangeOriginalToMinifiedMap.build(
+ updateOutlineCallsiteInformation.newMappedRanges);
+ Int2IntSortedMap newPositionMap = new Int2IntLinkedOpenHashMap();
+ outlineInfo
+ .getPositions()
+ .forEach(
+ (originalPosition, destination) -> {
+ originalToMinifiedMap.visitMinified(
+ originalPosition,
+ newMinified -> {
+ newPositionMap.put(newMinified, destination);
+ });
+ });
+ outlineInfo.setPositionsInternal(newPositionMap);
+ newMethodName = updateOutlineCallsiteInformation.newMethodName;
+ }
+ // Holder, return type or formals could have changed the outline descriptor.
+ MethodReference outline = outlineInfo.getOutline();
+ ClassReference newHolder =
+ mapTypeReference(inverse, outline.getHolderClass()).asClass();
+ outlineInfo.setOutlineInternal(
+ Reference.method(
+ newHolder,
+ newMethodName,
+ mapTypeReferences(inverse, outline.getFormalTypes()),
+ mapTypeReference(inverse, outline.getReturnType())));
+ newOutlineCallsiteInfo.put(
+ new ClassDescriptorAndMethodName(
+ newHolder.getTypeName(), holderAndMethodNameOfOutline.getMethodName()),
+ outlineInfo);
+ });
+ newOutlineCallsiteInfo.putAll(current.outlineCallsiteInformation);
+ outlineCallsiteInformation = newOutlineCallsiteInfo;
+ }
+
+ public void addNewOutlineCallsiteInformation(
+ MethodReference outline, OutlineCallsiteMappingInformation outlineCallsiteInfo) {
+ outlineCallsiteInformation.put(
+ new ClassDescriptorAndMethodName(
+ outline.getHolderClass().getTypeName(), outline.getMethodName()),
+ outlineCallsiteInfo);
+ }
+
+ public UpdateOutlineCallsiteInformation getUpdateOutlineCallsiteInformation(
+ String originalHolder, String originalMethodName, String newMethodName) {
+ return outlineSourcePositionsUpdated.computeIfAbsent(
+ new ClassDescriptorAndMethodName(originalHolder, originalMethodName),
+ ignore -> new UpdateOutlineCallsiteInformation(newMethodName));
+ }
+
+ private List<TypeReference> mapTypeReferences(
+ Map<String, String> typeNameMap, List<TypeReference> typeReferences) {
+ return ListUtils.map(typeReferences, typeRef -> mapTypeReference(typeNameMap, typeRef));
+ }
+
+ private TypeReference mapTypeReference(
+ Map<String, String> typeNameMap, TypeReference typeReference) {
+ if (typeReference == null || typeReference.isPrimitive()) {
+ return typeReference;
+ }
+ if (typeReference.isArray()) {
+ ArrayReference arrayReference = typeReference.asArray();
+ return Reference.array(
+ mapTypeReference(typeNameMap, arrayReference.getBaseType()),
+ arrayReference.getDimensions());
+ } else {
+ assert typeReference.isClass();
+ String newTypeName = typeNameMap.get(typeReference.getTypeName());
+ return newTypeName == null ? typeReference : Reference.classFromTypeName(newTypeName);
+ }
+ }
+ }
+
+ private static class ClassDescriptorAndMethodName {
+
+ private final String holderTypeName;
+ private final String methodName;
+
+ public ClassDescriptorAndMethodName(String holderTypeName, String methodName) {
+ this.holderTypeName = holderTypeName;
+ this.methodName = methodName;
+ }
+
+ public String getHolderTypeName() {
+ return holderTypeName;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ClassDescriptorAndMethodName)) {
+ return false;
+ }
+ ClassDescriptorAndMethodName that = (ClassDescriptorAndMethodName) o;
+ return holderTypeName.equals(that.holderTypeName) && methodName.equals(that.methodName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(holderTypeName, methodName);
+ }
+ }
+
+ private static class UpdateOutlineCallsiteInformation {
+
+ private List<MappedRange> newMappedRanges;
+ private final String newMethodName;
+
+ private UpdateOutlineCallsiteInformation(String newMethodName) {
+ this.newMethodName = newMethodName;
+ }
+
+ private void setNewMappedRanges(List<MappedRange> mappedRanges) {
+ newMappedRanges = mappedRanges;
+ }
+ }
+
+ private static class MappedRangeOriginalToMinifiedMap {
+
+ private final Int2ReferenceMap<List<Integer>> originalToMinified;
+
+ private MappedRangeOriginalToMinifiedMap(Int2ReferenceMap<List<Integer>> originalToMinified) {
+ this.originalToMinified = originalToMinified;
+ }
+
+ private static MappedRangeOriginalToMinifiedMap build(List<MappedRange> mappedRanges) {
+ Int2ReferenceMap<List<Integer>> positionMap = new Int2ReferenceOpenHashMap<>();
+ for (MappedRange mappedRange : mappedRanges) {
+ Range originalRange = mappedRange.originalRange;
+ for (int position = originalRange.from; position <= originalRange.to; position++) {
+ // It is perfectly fine to have multiple minified ranges mapping to the same source, we
+ // just need to keep the additional information.
+ positionMap
+ .computeIfAbsent(position, ignoreArgument(ArrayList::new))
+ .add(mappedRange.minifiedRange.from + (position - originalRange.from));
+ }
+ }
+ return new MappedRangeOriginalToMinifiedMap(positionMap);
+ }
+
+ public int lookupFirst(int originalPosition) {
+ List<Integer> minifiedPositions = originalToMinified.get(originalPosition);
+ return minifiedPositions == null ? 0 : minifiedPositions.get(0);
+ }
+
+ public void visitMinified(int originalPosition, Consumer<Integer> consumer) {
+ List<Integer> minifiedPositions = originalToMinified.get(originalPosition);
+ if (minifiedPositions != null) {
+ minifiedPositions.forEach(consumer);
+ }
}
}
@@ -163,13 +384,23 @@
// one method since any shrinker should put in line numbers for overloads.
private final Map<String, SegmentTree<List<MappedRange>>> methodMembers = new HashMap<>();
private List<MappingInformation> additionalMappingInfo = null;
- private final ComposingSharedData sharedData;
- private ComposingClassBuilder(
- String originalName, String renamedName, ComposingSharedData sharedData) {
+ private ComposingData current;
+
+ /**
+ * Keeps track of the current original name which is different from originalName if this is a
+ * subsequent mapping.
+ */
+ private String currentOriginalName;
+
+ private ComposingClassBuilder(String originalName, String renamedName) {
this.originalName = originalName;
this.renamedName = renamedName;
- this.sharedData = sharedData;
+ }
+
+ public void setCurrentComposingData(ComposingData current, String currentMinifiedName) {
+ this.current = current;
+ this.currentOriginalName = currentMinifiedName;
}
public void setRenamedName(String renamedName) {
@@ -268,7 +499,8 @@
* long as the current mapped range is the same method and return a mapped range result
* containing all ranges for a method along with some additional information.
*/
- private MappedRangeResult getMappedRangesForMethod(List<MappedRange> mappedRanges, int index) {
+ private MappedRangeResult getMappedRangesForMethod(List<MappedRange> mappedRanges, int index)
+ throws MappingComposeException {
if (index >= mappedRanges.size()) {
return null;
}
@@ -297,10 +529,30 @@
&& !isInlineMappedRange(mappedRanges, i)) {
break;
}
+ // Register mapping information that is dependent on the residual naming to allow updating
+ // later on.
for (MappingInformation mappingInformation : thisMappedRange.getAdditionalMappingInfo()) {
if (mappingInformation.isRewriteFrameMappingInformation()) {
- sharedData.mappingInformationToPatchUp.add(
- mappingInformation.asRewriteFrameMappingInformation());
+ RewriteFrameMappingInformation rewriteFrameMappingInformation =
+ mappingInformation.asRewriteFrameMappingInformation();
+ rewriteFrameMappingInformation
+ .getConditions()
+ .forEach(
+ condition -> {
+ if (condition.isThrowsCondition()) {
+ current.rewriteFrameInformation.add(rewriteFrameMappingInformation);
+ }
+ });
+ } else if (mappingInformation.isOutlineCallsiteInformation()) {
+ OutlineCallsiteMappingInformation outlineCallsiteInfo =
+ mappingInformation.asOutlineCallsiteInformation();
+ MethodReference outline = outlineCallsiteInfo.getOutline();
+ if (outline == null) {
+ throw new MappingComposeException(
+ "Unable to compose outline call site information without outline key: "
+ + outlineCallsiteInfo.serialize());
+ }
+ current.addNewOutlineCallsiteInformation(outline, outlineCallsiteInfo);
}
}
seenMappedRanges.add(thisMappedRange);
@@ -345,6 +597,7 @@
Int2ReferenceMap<List<MappedRange>> mappedRangesForPosition =
getExistingMapping(existingRanges);
List<MappedRange> newComposedRanges = new ArrayList<>();
+ ComputedOutlineInformation computedOutlineInformation = new ComputedOutlineInformation();
for (int i = 0; i < newRanges.size(); i++) {
if (isInlineMappedRange(newRanges, i)) {
throw new MappingComposeException(
@@ -378,6 +631,7 @@
newComposedRanges,
newRange,
existingMappedRanges,
+ computedOutlineInformation,
newRange.minifiedRange.from,
newRange.minifiedRange.to);
} else {
@@ -403,6 +657,7 @@
newComposedRanges,
newRange,
existingMappedRanges,
+ computedOutlineInformation,
lastStartingMinifiedFrom,
position - 1);
lastStartingMinifiedFrom = position;
@@ -413,11 +668,41 @@
newComposedRanges,
newRange,
existingMappedRanges,
+ computedOutlineInformation,
lastStartingMinifiedFrom,
newRange.minifiedRange.to);
}
}
}
+ MappedRange lastComposedRange = ListUtils.last(newComposedRanges);
+ if (computedOutlineInformation.seenOutlineMappingInformation != null) {
+ current
+ .getUpdateOutlineCallsiteInformation(
+ currentOriginalName,
+ ListUtils.last(newRanges).signature.getName(),
+ lastComposedRange.renamedName)
+ .setNewMappedRanges(newRanges);
+ lastComposedRange.addMappingInformation(
+ computedOutlineInformation.seenOutlineMappingInformation,
+ ConsumerUtils.emptyConsumer());
+ }
+ if (!computedOutlineInformation.outlineCallsiteMappingInformationToPatchUp.isEmpty()) {
+ MappedRangeOriginalToMinifiedMap originalToMinifiedMap =
+ MappedRangeOriginalToMinifiedMap.build(newRanges);
+ List<OutlineCallsiteMappingInformation> outlineCallSites =
+ new ArrayList<>(computedOutlineInformation.outlineCallsiteMappingInformationToPatchUp);
+ outlineCallSites.sort(Comparator.comparing(mapping -> mapping.getOutline().toString()));
+ for (OutlineCallsiteMappingInformation outlineCallSite : outlineCallSites) {
+ Int2IntSortedMap positionMap = outlineCallSite.getPositions();
+ for (Integer keyPosition : positionMap.keySet()) {
+ int keyPositionInt = keyPosition;
+ int originalDestination = positionMap.get(keyPositionInt);
+ int newDestination = originalToMinifiedMap.lookupFirst(originalDestination);
+ positionMap.put(keyPositionInt, newDestination);
+ }
+ lastComposedRange.addMappingInformation(outlineCallSite, ConsumerUtils.emptyConsumer());
+ }
+ }
return newComposedRanges;
}
@@ -453,6 +738,7 @@
List<MappedRange> newComposedRanges,
MappedRange newMappedRange,
List<MappedRange> existingMappedRanges,
+ ComputedOutlineInformation computedOutlineInformation,
int lastStartingMinifiedFrom,
int position) {
Range existingRange = existingMappedRanges.get(0).minifiedRange;
@@ -485,7 +771,17 @@
existingMappedRange
.getAdditionalMappingInfo()
.forEach(
- info -> computedRange.addMappingInformation(info, ConsumerUtils.emptyConsumer()));
+ info -> {
+ if (info.isOutlineMappingInformation()) {
+ computedOutlineInformation.seenOutlineMappingInformation =
+ info.asOutlineMappingInformation();
+ } else if (info.isOutlineCallsiteInformation()) {
+ computedOutlineInformation.outlineCallsiteMappingInformationToPatchUp.add(
+ info.asOutlineCallsiteInformation());
+ } else {
+ computedRange.addMappingInformation(info, ConsumerUtils.emptyConsumer());
+ }
+ });
newComposedRanges.add(computedRange);
}
}
@@ -573,5 +869,11 @@
this.allRanges = allRanges;
}
}
+
+ private static class ComputedOutlineInformation {
+ private final Set<OutlineCallsiteMappingInformation>
+ outlineCallsiteMappingInformationToPatchUp = Sets.newIdentityHashSet();
+ private OutlineMappingInformation seenOutlineMappingInformation = null;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index 787a0bc..c7d53f9 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -66,6 +66,10 @@
return null;
}
+ public OutlineMappingInformation asOutlineMappingInformation() {
+ return null;
+ }
+
public OutlineCallsiteMappingInformation asOutlineCallsiteInformation() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
index 5af9615..efdb788 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
@@ -24,8 +24,8 @@
private static final String POSITIONS_KEY = "positions";
private static final String OUTLINE_KEY = "outline";
- private final Int2IntSortedMap positions;
- private final MethodReference outline;
+ private Int2IntSortedMap positions;
+ private MethodReference outline;
private OutlineCallsiteMappingInformation(Int2IntSortedMap positions, MethodReference outline) {
this.positions = positions;
@@ -72,6 +72,10 @@
return positions.getOrDefault(originalPosition, originalPosition);
}
+ public MethodReference getOutline() {
+ return outline;
+ }
+
public static OutlineCallsiteMappingInformation create(
Int2IntSortedMap positions, MethodReference outline) {
return new OutlineCallsiteMappingInformation(positions, outline);
@@ -112,4 +116,16 @@
onMappingInfo.accept(OutlineCallsiteMappingInformation.create(positionsMap, outline));
}
}
+
+ public void setOutlineInternal(MethodReference outline) {
+ this.outline = outline;
+ }
+
+ public Int2IntSortedMap getPositions() {
+ return positions;
+ }
+
+ public void setPositionsInternal(Int2IntSortedMap positions) {
+ this.positions = positions;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
index 1914431..54c392b 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
@@ -27,6 +27,11 @@
}
@Override
+ public OutlineMappingInformation asOutlineMappingInformation() {
+ return this;
+ }
+
+ @Override
public boolean allowOther(MappingInformation information) {
return true;
}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeMapVersionTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeMapVersionTest.java
index bbc6c01..c91527d 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeMapVersionTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeMapVersionTest.java
@@ -4,13 +4,14 @@
package com.android.tools.r8.mappingcompose;
-import static com.android.tools.r8.mappingcompose.ComposeHelpers.doubleToSingleQuote;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposeException;
import com.android.tools.r8.naming.MappingComposer;
import com.android.tools.r8.utils.StringUtils;
import org.junit.Test;
@@ -31,18 +32,20 @@
private static final String mappingFoo =
StringUtils.unixLines(
- "# { id: 'com.android.tools.r8.mapping', version: '1.0' }", "com.foo -> a:");
+ "# { id: 'com.android.tools.r8.mapping', version: '2.1' }", "com.foo -> a:");
private static final String mappingBar =
- StringUtils.unixLines("# { id: 'com.android.tools.r8.mapping', version: '2.0' }", "a -> b:");
- private static final String mappingResult =
- StringUtils.unixLines(
- "# {'id':'com.android.tools.r8.mapping','version':'2.0'}", "com.foo -> b:");
+ StringUtils.unixLines("# { id: 'com.android.tools.r8.mapping', version: '2.2' }", "a -> b:");
@Test
public void testCompose() throws Exception {
ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
- String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
- assertEquals(mappingResult, doubleToSingleQuote(composed));
+ MappingComposeException mappingComposeException =
+ assertThrows(
+ MappingComposeException.class,
+ () -> MappingComposer.compose(mappingForFoo, mappingForBar));
+ assertEquals(
+ "Composition of mapping files supported from map version 2.1.",
+ mappingComposeException.getMessage());
}
}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
index 98f1cd5..8ba1011 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.mappingcompose;
import static com.android.tools.r8.mappingcompose.ComposeHelpers.doubleToSingleQuote;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -26,12 +26,12 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ return getTestParameters().withNoneRuntime().build();
}
private static final String mappingFoo =
StringUtils.unixLines(
- "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
+ "# { id: 'com.android.tools.r8.mapping', version: '2.1' }",
"outline.Class -> a:",
" 1:2:int some.inlinee():75:76 -> a",
" 1:2:int outline():0 -> a",
@@ -41,24 +41,27 @@
" 5:5:int foo.bar.baz.outlineCaller(int):98:98 -> s",
" 5:5:int outlineCaller(int):24 -> s",
" 27:27:int outlineCaller(int):0:0 -> s",
- " # { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '1': 4, '2': 5 } }");
- private static final String mappingBar =
+ " # { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '1': 4, '2': 5 },"
+ + " 'outline':'La;a()I' }");
+ private static final String mappingBar = StringUtils.unixLines("a -> b:");
+ private static final String mappingBaz =
StringUtils.unixLines(
- "a -> b:",
+ "b -> c:",
" 4:5:int a():1:2 -> m",
- "x -> c:",
+ "x -> y:",
" 8:9:int s(int):4:5 -> o",
" 42:42:int s(int):27:27 -> o");
private static final String mappingResult =
StringUtils.unixLines(
- "# {'id':'com.android.tools.r8.mapping','version':'2.0'}",
- "outline.Callsite -> c:",
+ "# {'id':'com.android.tools.r8.mapping','version':'2.1'}",
+ "outline.Callsite -> y:",
" 8:8:int outlineCaller(int):23 -> o",
" 9:9:int foo.bar.baz.outlineCaller(int):98:98 -> o",
" 9:9:int outlineCaller(int):24 -> o",
" 42:42:int outlineCaller(int):0:0 -> o",
- " # { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '4': 8, '5': 9 } }",
- "outline.Class -> b:",
+ " #"
+ + " {'id':'com.android.tools.r8.outlineCallsite','positions':{'4':8,'5':9},'outline':'Lc;m()I'}",
+ "outline.Class -> c:",
" 4:5:int some.inlinee():75:76 -> m",
" 4:5:int outline():0 -> m",
" # {'id':'com.android.tools.r8.outline'}");
@@ -67,8 +70,8 @@
public void testCompose() throws Exception {
ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
- String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
- // TODO(b/242682464): Update this test when the link has been added to the mapping information.
- assertNotEquals(mappingResult, doubleToSingleQuote(composed));
+ ClassNameMapper mappingForBaz = ClassNameMapper.mapperFromString(mappingBaz);
+ String composed = MappingComposer.compose(mappingForFoo, mappingForBar, mappingForBaz);
+ assertEquals(mappingResult, doubleToSingleQuote(composed));
}
}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeRewriteFrameTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeRewriteFrameTest.java
index cae1f89..f8b6ebc 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeRewriteFrameTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeRewriteFrameTest.java
@@ -31,7 +31,7 @@
private static final String mappingFoo =
StringUtils.unixLines(
- "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
+ "# { id: 'com.android.tools.r8.mapping', version: '2.1' }",
"my.CustomException -> a:",
"foo.Bar -> x:",
" 4:4:void other.Class.inlinee():23:23 -> a",
@@ -40,13 +40,13 @@
+ "conditions: ['throws(La;)'], actions: ['removeInnerFrames(1)'] }");
private static final String mappingBar =
StringUtils.unixLines(
- "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
+ "# { id: 'com.android.tools.r8.mapping', version: '2.1' }",
"a -> b:",
"x -> c:",
" 8:8:void a(Other.Class):4:4 -> m");
private static final String mappingResult =
StringUtils.unixLines(
- "# {'id':'com.android.tools.r8.mapping','version':'2.0'}",
+ "# {'id':'com.android.tools.r8.mapping','version':'2.1'}",
"foo.Bar -> c:",
" 8:8:void other.Class.inlinee():23:23 -> m",
" 8:8:void caller(other.Class):7 -> m",
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeSyntheticTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSyntheticTest.java
index 20585e9..e91eed6 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeSyntheticTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSyntheticTest.java
@@ -31,7 +31,7 @@
private static final String mappingFoo =
StringUtils.unixLines(
- "# { id: 'com.android.tools.r8.mapping', version: '1.0' }",
+ "# { id: 'com.android.tools.r8.mapping', version: '2.1' }",
"com.foo -> a:",
"# { id: 'com.android.tools.r8.synthesized' }",
" int f -> a",
@@ -40,7 +40,7 @@
" # { id: 'com.android.tools.r8.synthesized' }");
private static final String mappingBar =
StringUtils.unixLines(
- "# { id: 'com.android.tools.r8.mapping', version: '1.0' }",
+ "# { id: 'com.android.tools.r8.mapping', version: '2.1' }",
"a -> b:",
" int a -> b",
"com.bar -> c:",
@@ -49,7 +49,7 @@
" # { id: 'com.android.tools.r8.synthesized' }");
private static final String mappingResult =
StringUtils.unixLines(
- "# {'id':'com.android.tools.r8.mapping','version':'1.0'}",
+ "# {'id':'com.android.tools.r8.mapping','version':'2.1'}",
"com.bar -> c:",
"# {'id':'com.android.tools.r8.synthesized'}",
" void bar() -> a",