-dontoptimize part I: parse/record n of optimization passes.

Bug: 36800551
Change-Id: I038879850555d268abc49dbfc6c6ad5c08a30885
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 71a4dc6..0338533 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -22,6 +22,8 @@
     private String packagePrefix = null;
     private boolean allowAccessModification = false;
     private boolean ignoreWarnings = false;
+    private boolean optimize = true;
+    private int optimizationPasses = 1;
     private boolean obfuscating = true;
     private boolean shrinking = true;
     private boolean printUsage = false;
@@ -63,6 +65,15 @@
       this.ignoreWarnings = ignoreWarnings;
     }
 
+    public void setOptimize(boolean optimize) {
+      this.optimize = optimize;
+    }
+
+    public void setOptimizationPasses(int optimizationPasses) {
+      // TODO(b/36800551): no-op until we have clear ideas about optimization passes.
+      // this.optimizationPasses = optimizationPasses;
+    }
+
     public void setObfuscating(boolean obfuscate) {
       this.obfuscating = obfuscate;
     }
@@ -131,6 +142,7 @@
           packagePrefix,
           allowAccessModification,
           ignoreWarnings,
+          optimize ? optimizationPasses : 0,
           obfuscating,
           shrinking,
           printUsage,
@@ -155,6 +167,7 @@
   private final String packagePrefix;
   private final boolean allowAccessModification;
   private final boolean ignoreWarnings;
+  private final int optimizationPasses;
   private final boolean obfuscating;
   private final boolean shrinking;
   private final boolean printUsage;
@@ -178,6 +191,7 @@
       String packagePrefix,
       boolean allowAccessModification,
       boolean ignoreWarnings,
+      int optimizationPasses,
       boolean obfuscating,
       boolean shrinking,
       boolean printUsage,
@@ -199,6 +213,7 @@
     this.packagePrefix = packagePrefix;
     this.allowAccessModification = allowAccessModification;
     this.ignoreWarnings = ignoreWarnings;
+    this.optimizationPasses = optimizationPasses;
     this.obfuscating = obfuscating;
     this.shrinking = shrinking;
     this.printUsage = printUsage;
@@ -259,6 +274,10 @@
     return ignoreWarnings;
   }
 
+  public int getOptimizationPasses() {
+    return optimizationPasses;
+  }
+
   public boolean isObfuscating() {
     return obfuscating;
   }
@@ -317,6 +336,7 @@
           ""                    /* package prefix */,
           false                 /* allowAccessModification */,
           false                 /* ignoreWarnings */,
+          1                     /* optimizationPasses */,
           false                 /* obfuscating */,
           false                 /* shrinking */,
           false                 /* printUsage */,
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 cc29125..17e5128 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -38,7 +38,6 @@
 
   private static final List<String> ignoredSingleArgOptions = ImmutableList
       .of("protomapping",
-          "optimizationpasses",
           "target");
   private static final List<String> ignoredOptionalSingleArgOptions = ImmutableList
       .of("keepdirectories", "runtype", "laststageoutput");
@@ -63,7 +62,7 @@
           "outjars",
           "adaptresourcefilecontents");
   private static final List<String> warnedFlagOptions = ImmutableList
-      .of("dontoptimize");
+      .of();
 
   // Those options are unsupported and are treated as compilation errors.
   // Just ignoring them would produce outputs incompatible with user expectations.
@@ -96,7 +95,7 @@
     private int position = 0;
     private Path baseDirectory;
 
-    public ProguardFileParser(Path path) throws IOException {
+    ProguardFileParser(Path path) throws IOException {
       this.path = path;
       contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
       baseDirectory = path.getParent();
@@ -149,6 +148,17 @@
       } else if (acceptString("whyareyoukeeping")) {
         ProguardKeepRule rule = parseWhyAreYouKeepingRule();
         configurationBuilder.addRule(rule);
+      } else if (acceptString("dontoptimize")) {
+        configurationBuilder.setOptimize(false);
+        System.out.println("WARNING: Ignoring option: -dontoptimize");
+      } else if (acceptString("optimizationpasses")) {
+        skipWhitespace();
+        Integer expectedOptimizationPasses = acceptInteger();
+        if (expectedOptimizationPasses == null) {
+          throw parseError("Missing n of \"-optimizationpasses n\"");
+        }
+        configurationBuilder.setOptimizationPasses(expectedOptimizationPasses);
+        System.out.println("WARNING: Ignoring option: -optimizationpasses");
       } else if (acceptString("dontobfuscate")) {
         configurationBuilder.setObfuscating(false);
       } else if (acceptString("dontshrink")) {
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 242a7d5..ad1a392 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -66,6 +66,12 @@
       VALID_PROGUARD_DIR + "overloadaggressively.flags";
   private static final String DONT_OPTIMIZE =
       VALID_PROGUARD_DIR + "dontoptimize.flags";
+  private static final String DONT_OPTIMIZE_OVERRIDES_PASSES =
+      VALID_PROGUARD_DIR + "dontoptimize-overrides-optimizationpasses.flags";
+  private static final String OPTIMIZATION_PASSES =
+      VALID_PROGUARD_DIR + "optimizationpasses.flags";
+  private static final String OPTIMIZATION_PASSES_WITHOUT_N =
+      INVALID_PROGUARD_DIR + "optimizationpasses-without-n.flags";
   private static final String SKIP_NON_PUBLIC_LIBRARY_CLASSES =
       VALID_PROGUARD_DIR + "skipnonpubliclibraryclasses.flags";
   private static final String PARSE_AND_SKIP_SINGLE_ARGUMENT =
@@ -357,10 +363,40 @@
   }
 
   @Test
-  public void parseDontOptimize()
-      throws IOException, ProguardRuleParserException {
+  public void parseDontOptimize() throws IOException, ProguardRuleParserException {
     ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
     parser.parse(Paths.get(DONT_OPTIMIZE));
+    ProguardConfiguration config = parser.getConfig();
+    assertTrue(config.getOptimizationPasses() == 0);
+  }
+
+  @Test
+  public void parseDontOptimizeOverridesPasses() throws IOException, ProguardRuleParserException {
+    ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+    parser.parse(Paths.get(DONT_OPTIMIZE_OVERRIDES_PASSES));
+    ProguardConfiguration config = parser.getConfig();
+    assertTrue(config.getOptimizationPasses() == 0);
+  }
+
+  @Test
+  public void parseOptimizationPasses() throws IOException, ProguardRuleParserException {
+    ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+    parser.parse(Paths.get(OPTIMIZATION_PASSES));
+    ProguardConfiguration config = parser.getConfig();
+    // TODO(b/36800551): optimizationPasses should not be set at the moment.
+    // assertTrue(config.getOptimizationPasses() == 8);
+    assertTrue(config.getOptimizationPasses() == 1);
+  }
+
+  @Test
+  public void parseOptimizationPassesError() throws IOException, ProguardRuleParserException {
+    try {
+      ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+      parser.parse(Paths.get(OPTIMIZATION_PASSES_WITHOUT_N));
+      fail();
+    } catch (ProguardRuleParserException e) {
+      assertTrue(e.getMessage().contains("Missing n"));
+    }
   }
 
   @Test
diff --git a/src/test/proguard/invalid/optimizationpasses-without-n.flags b/src/test/proguard/invalid/optimizationpasses-without-n.flags
new file mode 100644
index 0000000..d0ca252
--- /dev/null
+++ b/src/test/proguard/invalid/optimizationpasses-without-n.flags
@@ -0,0 +1,6 @@
+# Copyright (c) 2017, 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.
+
+# Should specify the number of optimization passes
+-optimizationpasses
diff --git a/src/test/proguard/valid/dontoptimize-overrides-optimizationpasses.flags b/src/test/proguard/valid/dontoptimize-overrides-optimizationpasses.flags
new file mode 100644
index 0000000..cfc365c
--- /dev/null
+++ b/src/test/proguard/valid/dontoptimize-overrides-optimizationpasses.flags
@@ -0,0 +1,7 @@
+# Copyright (c) 2017, 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.
+
+-dontoptimize
+# dontoptimize will set the number of optimization passes zero whatever you put below.
+-optimizationpasses 1337
diff --git a/src/test/proguard/valid/optimizationpasses.flags b/src/test/proguard/valid/optimizationpasses.flags
new file mode 100644
index 0000000..c21e025
--- /dev/null
+++ b/src/test/proguard/valid/optimizationpasses.flags
@@ -0,0 +1,5 @@
+# Copyright (c) 2017, 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.
+
+-optimizationpasses 8