Support reading main dex list files starting with a byte order mark (BOM)
Bug: 135898791
Change-Id: I7b5c1f8601a6274c02a32ec7a94370548d455a7b
diff --git a/src/main/java/com/android/tools/r8/utils/MainDexList.java b/src/main/java/com/android/tools/r8/utils/MainDexList.java
index 74034ef..f1e775b 100644
--- a/src/main/java/com/android/tools/r8/utils/MainDexList.java
+++ b/src/main/java/com/android/tools/r8/utils/MainDexList.java
@@ -43,6 +43,9 @@
int newLineIndex = lines.indexOf('\n', offset);
int lineEnd = newLineIndex == -1 ? lines.length() : newLineIndex;
String line = lines.substring(offset, lineEnd).trim();
+ if (lineNumber == 1) {
+ line = StringUtils.stripBOM(line);
+ }
if (!line.isEmpty()) {
try {
result.add(parseEntry(line, itemFactory));
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 15eec4a..addafe4 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -65,12 +65,14 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.MainDexList;
import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -343,14 +345,20 @@
"a/b/c/D.class",
"a/b/c/D$E.class"
);
- DexItemFactory factory = new DexItemFactory();
- Path mainDexList = temp.getRoot().toPath().resolve("valid.txt");
- FileUtils.writeTextFile(mainDexList, list);
- Set<DexType> types = parse(mainDexList, factory);
- for (String entry : list) {
- DexType type = factory.createType("L" + entry.replace(".class", "") + ";");
- assertTrue(types.contains(type));
- assertSame(type, MainDexList.parseEntry(entry, factory));
+ for (Boolean addBOM : BooleanUtils.values()) {
+ DexItemFactory factory = new DexItemFactory();
+ Path mainDexList = temp.getRoot().toPath().resolve("valid.txt");
+ FileUtils.writeTextFile(
+ mainDexList,
+ list.stream()
+ .map(name -> name.startsWith("A") && addBOM ? StringUtils.BOM + name : name)
+ .collect(Collectors.toList()));
+ Set<DexType> types = parse(mainDexList, factory);
+ for (String entry : list) {
+ DexType type = factory.createType("L" + entry.replace(".class", "") + ";");
+ assertTrue(types.contains(type));
+ assertSame(type, MainDexList.parseEntry(entry, factory));
+ }
}
}
@@ -376,18 +384,27 @@
parse(mainDexList, factory);
}
+ enum TestMode {
+ FROM_CLASS_NAMES,
+ FROM_FILE,
+ FROM_FILE_WITH_BOM
+ }
+
private Path runD8WithMainDexList(
- CompilationMode mode, Path input, List<String> mainDexClasses, boolean useFile)
+ CompilationMode mode, Path input, List<String> mainDexClasses, TestMode testMode)
throws Exception {
Path testDir = temp.newFolder().toPath();
Path listFile = testDir.resolve("main-dex-list.txt");
- if (mainDexClasses != null && useFile) {
- FileUtils.writeTextFile(
- listFile,
- mainDexClasses
- .stream()
+ if (mainDexClasses != null
+ && (testMode == TestMode.FROM_FILE || testMode == TestMode.FROM_FILE_WITH_BOM)) {
+ List<String> lines =
+ mainDexClasses.stream()
.map(clazz -> clazz.replace('.', '/') + ".class")
- .collect(Collectors.toList()));
+ .collect(Collectors.toList());
+ if (testMode == TestMode.FROM_FILE_WITH_BOM) {
+ lines.set(0, StringUtils.BOM + lines.get(0));
+ }
+ FileUtils.writeTextFile(listFile, lines);
}
D8Command.Builder builder =
@@ -396,7 +413,7 @@
.setMode(mode)
.setOutput(testDir, OutputMode.DexIndexed);
if (mainDexClasses != null) {
- if (useFile) {
+ if (testMode == TestMode.FROM_FILE) {
builder.addMainDexListFiles(listFile);
} else {
builder.addMainDexClasses(mainDexClasses);
@@ -416,21 +433,25 @@
if (allClasses) {
// If all classes are passed add a run without a main-dex list as well.
testDirs.put(
- runD8WithMainDexList(mode, input, null, true),
+ runD8WithMainDexList(mode, input, null, TestMode.FROM_CLASS_NAMES),
mode.toString() + ": without a main-dex list");
}
testDirs.put(
- runD8WithMainDexList(mode, input, mainDexClasses, true),
+ runD8WithMainDexList(mode, input, mainDexClasses, TestMode.FROM_FILE),
mode.toString() + ": main-dex list files");
testDirs.put(
- runD8WithMainDexList(mode, input, mainDexClasses, false),
+ runD8WithMainDexList(mode, input, mainDexClasses, TestMode.FROM_FILE_WITH_BOM),
+ mode.toString() + ": main-dex list files (with BOM)");
+ testDirs.put(
+ runD8WithMainDexList(mode, input, mainDexClasses, TestMode.FROM_CLASS_NAMES),
mode.toString() + ": main-dex classes");
if (mainDexClasses != null) {
testDirs.put(
- runD8WithMainDexList(mode, input, Lists.reverse(mainDexClasses), true),
+ runD8WithMainDexList(mode, input, Lists.reverse(mainDexClasses), TestMode.FROM_FILE),
mode.toString() + ": main-dex list files (reversed)");
testDirs.put(
- runD8WithMainDexList(mode, input, Lists.reverse(mainDexClasses), false),
+ runD8WithMainDexList(
+ mode, input, Lists.reverse(mainDexClasses), TestMode.FROM_CLASS_NAMES),
mode.toString() + ": main-dex classes (reversed)");
}