Better Proguard configuration parser error for invalid options statring with keepclass
Also add an "arrow" to the exception text pointing to the location
on the erronous line.
R=herhut@google.com
Change-Id: I079dc7fe0400a2df783390abfa90366c1a026551
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 69db32d..965b1c0 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -20,6 +20,7 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
@@ -373,6 +374,10 @@
} else if (acceptString("eswithmembernames")) {
builder.setType(ProguardKeepRuleType.KEEP_CLASSES_WITH_MEMBERS);
builder.getModifiersBuilder().allowsShrinking = true;
+ } else {
+ // The only path to here is through "-keep" followed by "class".
+ unacceptString("-keepclass");
+ throw parseError("Unknown option");
}
} else {
builder.setType(ProguardKeepRuleType.KEEP);
@@ -903,6 +908,15 @@
return contents.substring(start, end);
}
+ private void unacceptString(String expected) {
+ assert position >= expected.length();
+ position -= expected.length();
+ for (int i = 0; i < expected.length(); i++) {
+ assert expected.charAt(i) == contents.charAt(position + i);
+ }
+ }
+
+
private void checkNotNegatedPattern() throws ProguardRuleParserException {
skipWhitespace();
if (acceptChar('!')) {
@@ -945,9 +959,11 @@
for (int lineNumber = 0; lineNumber < lines.length; lineNumber++) {
String line = lines[lineNumber];
if (remaining <= line.length() || lineNumber == lines.length - 1) {
- return path.toString() + ":" + (lineNumber + 1) + ":" + remaining + "\n" + line;
+ String arrow = CharBuffer.allocate(remaining).toString().replace( '\0', ' ' ) + '^';
+ return path.toString() + ":" + (lineNumber + 1) + ":" + remaining + "\n" + line
+ + '\n' + arrow;
}
- remaining -= (line.length() + 1); // include newline.
+ remaining -= (line.length() + 1); // Include newline.
}
return path.toString();
}
diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java
index a457e51..3f69c2e 100644
--- a/src/main/java/com/android/tools/r8/utils/FileUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.CompilationException;
import java.io.BufferedReader;
-import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -67,12 +66,7 @@
}
public static void writeTextFile(Path file, List<String> lines) throws IOException {
- try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
- for (String line : lines) {
- writer.write(line);
- writer.write("\n");
- }
- }
+ Files.write(file, lines);
}
public static void writeTextFile(Path file, String... lines) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 2362028..b20cb22 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -10,16 +10,18 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.graph.DexAccessFlags;
import com.android.tools.r8.graph.DexItemFactory;
import java.io.IOException;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-public class ProguardConfigurationParserTest {
+public class ProguardConfigurationParserTest extends TestBase {
private static final String VALID_PROGUARD_DIR = "src/test/proguard/valid/";
private static final String INVALID_PROGUARD_DIR = "src/test/proguard/invalid/";
@@ -331,4 +333,17 @@
ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
parser.parse(Paths.get(PARSE_AND_SKIP_SINGLE_ARGUMENT));
}
+
+ @Test
+ public void parseInvalidKeepClassOption() throws IOException, ProguardRuleParserException {
+ thrown.expect(ProguardRuleParserException.class);
+ thrown.expectMessage("Unknown option at ");
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+ Path proguardConfig = writeTextToTempFile(
+ "-keepclassx public class * { ",
+ " native <methods>; ",
+ "} "
+ );
+ parser.parse(proguardConfig);
+ }
}