[Partition] Add round-trip test for joining a partition
Bug: b/274893426
Bug: b/274735214
Change-Id: I05de70045f5721ce5d7cf917ede1479c1124f34c
diff --git a/src/main/java/com/android/tools/r8/retrace/PartitionedToProguardMappingConverter.java b/src/main/java/com/android/tools/r8/retrace/PartitionedToProguardMappingConverter.java
new file mode 100644
index 0000000..b6181dc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/PartitionedToProguardMappingConverter.java
@@ -0,0 +1,117 @@
+// Copyright (c) 2023, 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.retrace;
+
+import static com.google.common.base.Predicates.alwaysTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.LineReader;
+import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.retrace.internal.MappingPartitionMetadataInternal;
+import com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.ProguardMapReaderWithFilteringInputBuffer;
+import com.android.tools.r8.retrace.internal.RetracePartitionException;
+import com.android.tools.r8.utils.ChainableStringConsumer;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+public class PartitionedToProguardMappingConverter {
+
+ private final StringConsumer consumer;
+ private final MappingPartitionFromKeySupplier partitionSupplier;
+ private final byte[] metadata;
+ private final DiagnosticsHandler diagnosticsHandler;
+
+ private PartitionedToProguardMappingConverter(
+ StringConsumer consumer,
+ MappingPartitionFromKeySupplier partitionSupplier,
+ byte[] metadata,
+ DiagnosticsHandler diagnosticsHandler) {
+ this.consumer = consumer;
+ this.partitionSupplier = partitionSupplier;
+ this.metadata = metadata;
+ this.diagnosticsHandler = diagnosticsHandler;
+ }
+
+ public void run() throws RetracePartitionException {
+ MappingPartitionMetadataInternal metadataInternal =
+ MappingPartitionMetadataInternal.deserialize(
+ metadata, MapVersion.MAP_VERSION_UNKNOWN, diagnosticsHandler);
+ if (!metadataInternal.canGetPartitionKeys()) {
+ throw new RetracePartitionException("Cannot obtain all partition keys from metadata");
+ }
+ // TODO(b/274893426): Account for preamble.
+ ClassNameMapper classNameMapper = ClassNameMapper.builder().build();
+ for (String partitionKey : metadataInternal.getPartitionKeys()) {
+ LineReader reader =
+ new ProguardMapReaderWithFilteringInputBuffer(
+ new ByteArrayInputStream(partitionSupplier.get(partitionKey)), alwaysTrue(), true);
+ try {
+ classNameMapper =
+ ClassNameMapper.mapperFromLineReaderWithFiltering(
+ reader, metadataInternal.getMapVersion(), diagnosticsHandler, true, true)
+ .combine(classNameMapper);
+ } catch (IOException e) {
+ throw new RetracePartitionException(e);
+ }
+ }
+ classNameMapper.sorted().write(new ProguardMapWriter(consumer, diagnosticsHandler));
+ }
+
+ private static class ProguardMapWriter implements ChainableStringConsumer {
+
+ private final StringConsumer consumer;
+ private final DiagnosticsHandler diagnosticsHandler;
+
+ private ProguardMapWriter(StringConsumer consumer, DiagnosticsHandler diagnosticsHandler) {
+ this.consumer = consumer;
+ this.diagnosticsHandler = diagnosticsHandler;
+ }
+
+ @Override
+ public ProguardMapWriter accept(String string) {
+ consumer.accept(string, diagnosticsHandler);
+ return this;
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private StringConsumer consumer;
+ private MappingPartitionFromKeySupplier partitionSupplier;
+ private byte[] metadata;
+ private DiagnosticsHandler diagnosticsHandler;
+
+ public Builder setConsumer(StringConsumer consumer) {
+ this.consumer = consumer;
+ return this;
+ }
+
+ public Builder setPartitionSupplier(MappingPartitionFromKeySupplier partitionSupplier) {
+ this.partitionSupplier = partitionSupplier;
+ return this;
+ }
+
+ public Builder setMetadata(byte[] metadata) {
+ this.metadata = metadata;
+ return this;
+ }
+
+ public Builder setDiagnosticsHandler(DiagnosticsHandler diagnosticsHandler) {
+ this.diagnosticsHandler = diagnosticsHandler;
+ return this;
+ }
+
+ public PartitionedToProguardMappingConverter build() {
+ return new PartitionedToProguardMappingConverter(
+ consumer, partitionSupplier, metadata, diagnosticsHandler);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
index 8c8ee27..0cee013 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
@@ -17,6 +17,7 @@
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.Collection;
public interface MappingPartitionMetadataInternal extends MappingPartitionMetadata {
@@ -24,12 +25,11 @@
MapVersion getMapVersion();
- default boolean isObfuscatedTypeNameAsKeyMetadataWithPartitionNames() {
+ default boolean canGetPartitionKeys() {
return false;
}
- default ObfuscatedTypeNameAsKeyMetadataWithPartitionNames
- asObfuscatedTypeNameAsKeyMetadataWithPartitionNames() {
+ default Collection<String> getPartitionKeys() {
return null;
}
@@ -150,14 +150,13 @@
}
@Override
- public boolean isObfuscatedTypeNameAsKeyMetadataWithPartitionNames() {
+ public boolean canGetPartitionKeys() {
return true;
}
@Override
- public ObfuscatedTypeNameAsKeyMetadataWithPartitionNames
- asObfuscatedTypeNameAsKeyMetadataWithPartitionNames() {
- return this;
+ public Collection<String> getPartitionKeys() {
+ return metadataPartitionCollection.getPartitionKeys();
}
// The format is:
@@ -189,9 +188,5 @@
mapVersion,
new LazyMetadataPartitionCollection(bytes, partitionCollectionStartIndex, bytes.length));
}
-
- public MetadataPartitionCollection getMetadataPartitionCollection() {
- return metadataPartitionCollection;
- }
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
index 68adc36..06ede47 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
@@ -132,11 +132,16 @@
(classNameMapper, classNamingForNameMapper, payload) -> {
Set<String> seenMappings = new HashSet<>();
StringBuilder payloadWithClassReferences = new StringBuilder();
+ Map<String, String> lookupMap =
+ classNameMapper.getObfuscatedToOriginalMapping().inverse;
classNamingForNameMapper.visitAllFullyQualifiedReferences(
holder -> {
if (seenMappings.add(holder)) {
payloadWithClassReferences.append(
- getSourceFileMapping(holder, classNameMapper.getSourceFile(holder)));
+ getSourceFileMapping(
+ holder,
+ lookupMap.get(holder),
+ classNameMapper.getSourceFile(holder)));
}
});
payloadWithClassReferences.append(payload);
@@ -165,13 +170,14 @@
}
}
- private String getSourceFileMapping(String className, String sourceFile) {
+ private String getSourceFileMapping(
+ String className, String obfuscatedClassName, String sourceFile) {
if (sourceFile == null) {
return "";
}
return className
+ " -> "
- + className
+ + (obfuscatedClassName == null ? className : obfuscatedClassName)
+ ":"
+ "\n # "
+ FileNameInformation.build(sourceFile).serialize()
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracePartitionException.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracePartitionException.java
index dd183f2..7e6e924 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracePartitionException.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracePartitionException.java
@@ -12,4 +12,8 @@
public RetracePartitionException(String message) {
super(message);
}
+
+ public RetracePartitionException(Exception e) {
+ super(e);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 45322ff..74d850c 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -2026,4 +2026,15 @@
}
return byteRead1 == byteRead2;
}
+
+ protected void assertListsAreEqual(List<String> expected, List<String> actual) {
+ int minLines = Math.min(expected.size(), actual.size());
+ for (int i = 0; i < minLines; i++) {
+ assertEquals(expected.get(i), actual.get(i));
+ }
+ if (expected.size() != actual.size()) {
+ assertEquals(
+ "", expected.size() > actual.size() ? expected.get(minLines) : actual.get(minLines));
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionAndJoinIdentityTest.java b/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionAndJoinIdentityTest.java
new file mode 100644
index 0000000..1bd8f56
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionAndJoinIdentityTest.java
@@ -0,0 +1,88 @@
+// Copyright (c) 2023, 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.retrace.partition;
+
+import static org.junit.Assert.assertNotNull;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessagesImpl;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.retrace.MappingPartitionMetadata;
+import com.android.tools.r8.retrace.PartitionedToProguardMappingConverter;
+import com.android.tools.r8.retrace.ProguardMapPartitioner;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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 RetracePartitionAndJoinIdentityTest extends TestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public RetracePartitionAndJoinIdentityTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ @Test
+ public void testPartitionAndJoin() throws Exception {
+ Path mappingFile =
+ ToolHelper.RETRACE_MAPS_DIR.resolve(
+ "ad5c3e88ef2bae5ef324eb225fbc57345cd57863-r8lib.jar.map");
+ ProguardMapProducer proguardMapProducer = ProguardMapProducer.fromPath(mappingFile);
+ TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
+ Map<String, byte[]> partitions = new HashMap<>();
+ MappingPartitionMetadata metadataData =
+ ProguardMapPartitioner.builder(diagnosticsHandler)
+ .setProguardMapProducer(proguardMapProducer)
+ .setPartitionConsumer(
+ partition -> partitions.put(partition.getKey(), partition.getPayload()))
+ .build()
+ .run();
+ assertNotNull(metadataData);
+ diagnosticsHandler.assertNoMessages();
+
+ StringBuilder builder = new StringBuilder();
+ PartitionedToProguardMappingConverter.builder()
+ .setMetadata(metadataData.getBytes())
+ .setDiagnosticsHandler(diagnosticsHandler)
+ .setConsumer((string, handler) -> builder.append(string))
+ .setPartitionSupplier(partitions::get)
+ .build()
+ .run();
+ List<String> joinedMapLines = StringUtils.splitLines(builder.toString());
+ // TODO(b/274735214): Partitioning does not capture the preamble of the mapping file yet, so we
+ // discard it before checking equality.
+ List<String> lines = Files.readAllLines(mappingFile);
+ List<String> filteredLines = lines.subList(computeFirstLine(lines), lines.size());
+ assertListsAreEqual(filteredLines, joinedMapLines);
+ }
+
+ private int computeFirstLine(List<String> lines) {
+ int firstLine = 0;
+ for (int i = 0; i < lines.size(); i++) {
+ String currentLine = lines.get(i).trim();
+ if (!currentLine.startsWith("#")
+ && currentLine.contains(" -> ")
+ && currentLine.endsWith(":")) {
+ firstLine = i;
+ break;
+ }
+ }
+ return firstLine;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataPartitionNamesTest.java b/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataPartitionNamesTest.java
index 8d40215..6db000b 100644
--- a/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataPartitionNamesTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataPartitionNamesTest.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.retrace.ProguardMapProducer;
import com.android.tools.r8.retrace.internal.MappingPartitionKeyStrategy;
import com.android.tools.r8.retrace.internal.MappingPartitionMetadataInternal;
-import com.android.tools.r8.retrace.internal.MappingPartitionMetadataInternal.ObfuscatedTypeNameAsKeyMetadataWithPartitionNames;
import com.android.tools.r8.retrace.internal.ProguardMapPartitionerOnClassNameToText.ProguardMapPartitionerBuilderImplInternal;
import com.android.tools.r8.utils.StringUtils;
import java.util.ArrayList;
@@ -84,11 +83,7 @@
MappingPartitionMetadataInternal mappingPartitionMetadata =
MappingPartitionMetadataInternal.deserialize(
bytes, MapVersion.MAP_VERSION_NONE, diagnosticsHandler);
- assertTrue(mappingPartitionMetadata.isObfuscatedTypeNameAsKeyMetadataWithPartitionNames());
- ObfuscatedTypeNameAsKeyMetadataWithPartitionNames obfuscatedTypeNameMetadata =
- mappingPartitionMetadata.asObfuscatedTypeNameAsKeyMetadataWithPartitionNames();
- assertEquals(
- expectedPartitionKeys,
- obfuscatedTypeNameMetadata.getMetadataPartitionCollection().getPartitionKeys());
+ assertTrue(mappingPartitionMetadata.canGetPartitionKeys());
+ assertEquals(expectedPartitionKeys, mappingPartitionMetadata.getPartitionKeys());
}
}
diff --git a/third_party/r8mappings.tar.gz.sha1 b/third_party/r8mappings.tar.gz.sha1
index a00ac52..424ff92 100644
--- a/third_party/r8mappings.tar.gz.sha1
+++ b/third_party/r8mappings.tar.gz.sha1
@@ -1 +1 @@
-baaf8e15c9f54677c30caf070a22319ccd46539c
\ No newline at end of file
+10daa67ab31114fd4649c996e1ac82c63a5b5e4e
\ No newline at end of file