Merge "Devirtualization from invoke-interface to invoke-virtual."
diff --git a/build.gradle b/build.gradle
index 9b8d59b..f857f9e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -300,6 +300,7 @@
                 "android_jar/lib-v25",
                 "android_jar/lib-v26",
                 "proguard/proguard5.2.1",
+                "proguard/proguard6.0",
                 "gradle/gradle",
                 "jdwp-tests",
                 "jasmin",
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 5d77ad3..fed4a00 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "v1.1.7-dev";
+  public static final String LABEL = "v1.1.8-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index 69fb348..bfc0a9f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -195,11 +195,13 @@
   private void emitDebugPosition(int pc, Position position) {
     assert !position.equals(emittedPosition);
     if (startLine == NO_LINE_INFO) {
-      if (position.synthetic) {
+      assert emittedPosition.isNone();
+      if (position.synthetic && position.callerPosition == null) {
         // Ignore synthetic positions prior to any actual position.
+        // We do need to preserve synthetic position establishing the stack frame for inlined
+        // methods.
         return;
       }
-      assert emittedPosition.isNone();
       startLine = position.line;
       emittedPosition = new Position(position.line, null, method.method, null);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
index cde22b0..8d522de 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
@@ -31,6 +31,7 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
+    assert getPosition().isSome() && !getPosition().synthetic;
     builder.addDebugPosition(this);
   }
 
@@ -73,6 +74,7 @@
 
   @Override
   public void buildCf(CfBuilder builder) {
+    assert getPosition().isSome() && !getPosition().synthetic;
     // All redundant debug positions are removed. Remaining ones must force a pc advance.
     builder.add(new CfNop());
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index 96b2122..3ad0168 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -984,14 +984,7 @@
       int source = builder.getInfo(jump).getOffset();
       Info targetInfo = builder.getTargetInfo(jump.getTarget());
       int relativeOffset = targetInfo.getOffset() - source;
-      // Emit a return if the target is a return and the size of the return is the computed
-      // size of this instruction.
-      Return ret = targetInfo.getIR().asReturn();
-      if (ret != null && size == targetInfo.getSize() && ret.getPosition().isNone()) {
-        Instruction dex = ret.createDexInstruction(builder);
-        dex.setOffset(getOffset()); // for better printing of the dex code.
-        instructions.add(dex);
-      } else if (size == relativeOffset) {
+      if (size == relativeOffset) {
         // We should never generate a goto targeting the next instruction. However, if we do
         // we replace it with nops. This works around a dalvik bug where the dalvik tracing
         // jit crashes on 'goto next instruction' on Android 4.1.1.
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 55e4b83..b9bbe5a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -136,7 +136,7 @@
 
   @Override
   public void buildPrelude(IRBuilder builder) {
-    currentPosition = Position.none();
+    currentPosition = Position.synthetic(0, method, null);
     if (code.incomingRegisterSize == 0) {
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 98c1015..6364c82 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -396,10 +396,6 @@
     // necessary.
     ir.splitCriticalEdges();
 
-    if (options.testing.invertConditionals) {
-      invertConditionalsForTesting(ir);
-    }
-
     // Create block order and make sure that all blocks are immediately followed by their
     // fallthrough block if any.
     ir.traceBlocks();
@@ -440,7 +436,7 @@
           } else {
             current = position;
           }
-        } else if (position.isSome() && !position.equals(current)) {
+        } else if (position.isSome() && !position.synthetic && !position.equals(current)) {
           DebugPosition positionChange = new DebugPosition();
           positionChange.setPosition(position);
           it.previous();
@@ -2006,14 +2002,6 @@
     return type != NumericType.FLOAT && type != NumericType.DOUBLE && type != NumericType.LONG;
   }
 
-  private static void invertConditionalsForTesting(IRCode code) {
-    for (BasicBlock block : code.blocks) {
-      if (block.exit().isIf()) {
-        block.exit().asIf().invert();
-      }
-    }
-  }
-
   @Override
   public String toString() {
     StringBuilder builder = new StringBuilder();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 4c4ca79..f9bcf1d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.analysis.constant.SparseConditionalConstantPropagation;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeEnvironment;
+import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.LambdaRewriter;
@@ -517,6 +518,14 @@
     }
   }
 
+  private static void invertConditionalsForTesting(IRCode code) {
+    for (BasicBlock block : code.blocks) {
+      if (block.exit().isIf()) {
+        block.exit().asIf().invert();
+      }
+    }
+  }
+
   private void rewriteCode(DexEncodedMethod method,
       OptimizationFeedback feedback,
       Predicate<DexEncodedMethod> isProcessedConcurrently,
@@ -597,6 +606,12 @@
     codeRewriter.rewriteSwitch(code);
     codeRewriter.processMethodsNeverReturningNormally(code);
     codeRewriter.simplifyIf(code, typeEnvironment);
+
+    if (options.testing.invertConditionals) {
+      invertConditionalsForTesting(code);
+      code.traceBlocks();
+    }
+
     if (options.enableNonNullTracking && nonNullTracker != null) {
       nonNullTracker.cleanupNonNull(code);
       assert code.isConsistentSSA();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 69ecb83..12429e9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -186,6 +186,9 @@
   // Canonicalized positions to lower memory usage.
   private final Int2ReferenceMap<Position> canonicalPositions = new Int2ReferenceOpenHashMap<>();
 
+  // Synthetic position with line = 0.
+  private Position preamblePosition = null;
+
   // Cooked position to indicate positions in synthesized code (ie, for synchronization).
   private Position syntheticPosition = null;
 
@@ -262,6 +265,8 @@
 
   @Override
   public void buildPrelude(IRBuilder builder) {
+    currentPosition = getPreamblePosition();
+
     // Record types for arguments.
     Int2ReferenceMap<ValueType> argumentLocals = recordArgumentTypes();
     Int2ReferenceMap<ValueType> initializedLocals = new Int2ReferenceOpenHashMap<>(argumentLocals);
@@ -327,8 +332,6 @@
       locals = state.openLocals(getOffset(initialLabel));
     }
 
-    currentPosition = Position.none();
-
     // Build the actual argument instructions now that type and debug information is known
     // for arguments.
     buildArgumentInstructions(builder);
@@ -457,7 +460,7 @@
   private void buildExceptionalPostlude(IRBuilder builder) {
     assert isSynchronized();
     generatingMethodSynchronization = true;
-    currentPosition = getSyntheticPosition();
+    currentPosition = getExceptionalExitPosition();
     buildMonitorExit(builder);
     builder.addThrow(getMoveExceptionRegister());
     generatingMethodSynchronization = false;
@@ -503,7 +506,9 @@
     // writes after the line has changed and thus causing locals to become visible too late.
     currentPosition =
         getDebugPositionAtOffset(
-            insn instanceof LabelNode ? instructionIndex - 1 : instructionIndex);
+            ((instructionIndex > 0) && (insn instanceof LabelNode))
+                ? instructionIndex - 1
+                : instructionIndex);
 
     build(insn, builder);
 
@@ -2906,10 +2911,11 @@
   @Override
   public Position getDebugPositionAtOffset(int offset) {
     if (offset == EXCEPTIONAL_SYNC_EXIT_OFFSET) {
-      return getSyntheticPosition();
+      return getExceptionalExitPosition();
     }
     int index = instructionIndex(offset);
     if (index < 0 || instructionCount() <= index) {
+      assert false;
       return Position.none();
     }
     AbstractInsnNode insn = node.instructions.get(index);
@@ -2923,7 +2929,7 @@
       LineNumberNode line = (LineNumberNode) insn;
       return getCanonicalPosition(line.line);
     }
-    return Position.none();
+    return getPreamblePosition();
   }
 
   @Override
@@ -2936,12 +2942,19 @@
         line, l -> new Position(l, null, method, callerPosition));
   }
 
+  private Position getPreamblePosition() {
+    if (preamblePosition == null) {
+      preamblePosition = Position.synthetic(0, method, null);
+    }
+    return preamblePosition;
+  }
+
   // If we need to emit a synthetic position for exceptional monitor exits, we try to cook up a
   // position that is not actually a valid program position, so as not to incorrectly position the
   // user on an exit that is not the actual exit being taken. Our heuristic for this is that if the
   // method has at least two positions we use the first position minus one as the synthetic exit.
   // If the method only has one position it is safe to just use that position.
-  private Position getSyntheticPosition() {
+  private Position getExceptionalExitPosition() {
     if (syntheticPosition == null) {
       int min = Integer.MAX_VALUE;
       int max = Integer.MIN_VALUE;
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 9cf59b3..ca62583 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -46,19 +46,28 @@
 
   private static final List<String> IGNORED_SINGLE_ARG_OPTIONS = ImmutableList
       .of("protomapping",
-          "target");
+          "target"
+      );
   private static final List<String> IGNORED_OPTIONAL_SINGLE_ARG_OPTIONS = ImmutableList
-      .of("keepdirectories", "runtype", "laststageoutput");
+      .of("keepdirectories",
+          "runtype",
+          "laststageoutput"
+      );
   private static final List<String> IGNORED_FLAG_OPTIONS = ImmutableList
-      .of("forceprocessing", "dontusemixedcaseclassnames",
-          "dontpreverify", "experimentalshrinkunusedprotofields",
+      .of("forceprocessing",
+          "dontusemixedcaseclassnames",
+          "dontpreverify",
+          "experimentalshrinkunusedprotofields",
           "filterlibraryjarswithorginalprogramjars",
           "dontskipnonpubliclibraryclasses",
           "dontskipnonpubliclibraryclassmembers",
-          "invokebasemethod");
+          "invokebasemethod",
+          "android"
+      );
   private static final List<String> IGNORED_CLASS_DESCRIPTOR_OPTIONS = ImmutableList
       .of("isclassnamestring",
-          "whyarenotsimple");
+          "whyarenotsimple"
+      );
 
   private static final List<String> WARNED_SINGLE_ARG_OPTIONS = ImmutableList
       .of("dontnote",
@@ -66,9 +75,22 @@
           // TODO -outjars (http://b/37137994) and -adaptresourcefilecontents (http://b/37139570)
           // should be reported as errors, not just as warnings!
           "outjars",
-          "adaptresourcefilecontents");
+          "adaptresourcefilecontents"
+      );
   private static final List<String> WARNED_FLAG_OPTIONS = ImmutableList
-      .of();
+      .of(
+          // TODO(b/73707846): add support -addconfigurationdebugging
+          "addconfigurationdebugging"
+      );
+  private static final List<String> WARNED_CLASS_DESCRIPTOR_OPTIONS = ImmutableList
+      .of(
+          // TODO(b/73708157): add support -assumenoexternalsideeffects <class_spec>
+          "assumenoexternalsideeffects",
+          // TODO(b/73707404): add support -assumenoescapingparameters <class_spec>
+          "assumenoescapingparameters",
+          // TODO(b/73708085): add support -assumenoexternalreturnvalues <class_spec>
+          "assumenoexternalreturnvalues"
+      );
 
   // Those options are unsupported and are treated as compilation errors.
   // Just ignoring them would produce outputs incompatible with user expectations.
@@ -91,7 +113,7 @@
     if (configurationBuilder.isKeepParameterNames() && configurationBuilder.isObfuscating()) {
       // The flag -keepparameternames has only effect when minifying, so ignore it if we
       // are not.
-      reporter.fatalError(new StringDiagnostic(
+      throw reporter.fatalError(new StringDiagnostic(
           "-keepparameternames is not supported",
           configurationBuilder.getKeepParameterNamesOptionOrigin(),
           configurationBuilder.getKeepParameterNamesOptionPosition()));
@@ -181,14 +203,17 @@
       } else if (
           (option = Iterables.find(WARNED_SINGLE_ARG_OPTIONS,
               this::skipOptionWithSingleArg, null)) != null
-              || (option = Iterables.find(WARNED_FLAG_OPTIONS, this::skipFlag, null)) != null) {
+              || (option = Iterables.find(WARNED_FLAG_OPTIONS,
+                  this::skipFlag, null)) != null
+              || (option = Iterables.find(WARNED_CLASS_DESCRIPTOR_OPTIONS,
+                  this::skipOptionWithClassSpec, null)) != null) {
         warnIgnoringOptions(option, optionStart);
       } else if (
           (option = Iterables.find(UNSUPPORTED_FLAG_OPTIONS, this::skipFlag, null)) != null) {
         reporter.error(new StringDiagnostic(
             "Unsupported option: -" + option,
             origin,
-            getPostion(optionStart)));
+            getPosition(optionStart)));
       } else if (acceptString("renamesourcefileattribute")) {
         skipWhitespace();
         if (isOptionalArgumentGiven()) {
@@ -202,8 +227,7 @@
         ProguardKeepPackageNamesRule rule = parseKeepPackageNamesRule();
         configurationBuilder.addRule(rule);
       } else if (acceptString("keepparameternames")) {
-        configurationBuilder.setKeepParameterNames(true,
-            origin, getPostion(optionStart));
+        configurationBuilder.setKeepParameterNames(true, origin, getPosition(optionStart));
       } else if (acceptString("checkdiscard")) {
         ProguardCheckDiscardRule rule = parseCheckDiscardRule();
         configurationBuilder.addRule(rule);
@@ -220,9 +244,7 @@
         Integer expectedOptimizationPasses = acceptInteger();
         if (expectedOptimizationPasses == null) {
           throw reporter.fatalError(new StringDiagnostic(
-              "Missing n of \"-optimizationpasses n\"",
-              origin,
-              getPostion(optionStart)));
+              "Missing n of \"-optimizationpasses n\"", origin, getPosition(optionStart)));
         }
         warnIgnoringOptions("optimizationpasses", optionStart);
       } else if (acceptString("dontobfuscate")) {
@@ -249,8 +271,7 @@
         }
       } else if (acceptString("repackageclasses")) {
         if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.FLATTEN) {
-          warnOverridingOptions("repackageclasses", "flattenpackagehierarchy",
-              optionStart);
+          warnOverridingOptions("repackageclasses", "flattenpackagehierarchy", optionStart);
         }
         skipWhitespace();
         if (acceptChar('\'')) {
@@ -261,8 +282,7 @@
         }
       } else if (acceptString("flattenpackagehierarchy")) {
         if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.REPACKAGE) {
-          warnOverridingOptions("repackageclasses", "flattenpackagehierarchy",
-              optionStart);
+          warnOverridingOptions("repackageclasses", "flattenpackagehierarchy", optionStart);
           skipWhitespace();
           if (isOptionalArgumentGiven()) {
             skipSingleArgument();
@@ -331,15 +351,30 @@
         }
       } else if (acceptString("identifiernamestring")) {
         configurationBuilder.addRule(parseIdentifierNameStringRule());
+      } else if (acceptString("if")) {
+        // TODO(b/73708139): add support -if <class_spec>
+        ProguardKeepRule.Builder keepRuleBuilder = ProguardKeepRule.builder();
+        parseClassSpec(keepRuleBuilder, true);
+        ProguardKeepRule ifRule = keepRuleBuilder.build();
+        assert ifRule.getClassType() == ProguardClassType.CLASS;
+
+        // Required a subsequent keep rule.
+        skipWhitespace();
+        if (acceptString("-keep")) {
+          ProguardKeepRule subsequentRule = parseKeepRule();
+          warnIgnoringOptions("if", optionStart);
+        } else {
+          throw reporter.fatalError(new StringDiagnostic(
+              "Option -if without a subsequent keep rule.", origin, getPosition(optionStart)));
+        }
       } else {
         String unknownOption = acceptString();
-        reporter.error(new StringDiagnostic("Unknown option \"-" + unknownOption + "\"",
-            origin, getPostion(optionStart)));
+        reporter.error(new StringDiagnostic(
+            "Unknown option \"-" + unknownOption + "\"", origin, getPosition(optionStart)));
       }
       return true;
     }
 
-
     private void parseInclude() throws ProguardRuleParserException {
       TextPosition start = getPosition();
       Path included = parseFileName();
@@ -639,9 +674,8 @@
       } else if (acceptString("enum")) {
         builder.setClassType(ProguardClassType.ENUM);
       } else {
-        throw reporter
-            .fatalError(new StringDiagnostic("Expected [!]interface|@interface|class|enum",
-            origin, getPostion(start)));
+        throw reporter.fatalError(new StringDiagnostic(
+            "Expected [!]interface|@interface|class|enum", origin, getPosition(start)));
       }
     }
 
@@ -1199,28 +1233,25 @@
     private ProguardRuleParserException parseError(String message, TextPosition start,
         Throwable cause) {
       return new ProguardRuleParserException(message, snippetForPosition(start),
-          origin, getPostion(start), cause);
+          origin, getPosition(start), cause);
     }
 
     private ProguardRuleParserException parseError(String message, TextPosition start) {
       return new ProguardRuleParserException(message, snippetForPosition(start),
-          origin, getPostion(start));
+          origin, getPosition(start));
     }
 
     private void warnIgnoringOptions(String optionName, TextPosition start) {
       reporter.warning(new StringDiagnostic(
-          "Ignoring option: -" + optionName,
-          origin,
-          getPostion(start)));
+          "Ignoring option: -" + optionName, origin, getPosition(start)));
     }
 
     private void warnOverridingOptions(String optionName, String victim, TextPosition start) {
-      reporter.warning(
-          new StringDiagnostic("Option -" + optionName + " overrides -" + victim,
-              origin, getPostion(start)));
+      reporter.warning(new StringDiagnostic(
+          "Option -" + optionName + " overrides -" + victim, origin, getPosition(start)));
     }
 
-    private Position getPostion(TextPosition start) {
+    private Position getPosition(TextPosition start) {
       if (start.getOffset() == position) {
         return start;
       } else {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index cc325e2..0c0cd84 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -90,7 +90,9 @@
   private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
   private static final AndroidApiLevel DEFAULT_MIN_SDK = AndroidApiLevel.I;
 
-  private static final String PROGUARD = "third_party/proguard/proguard5.2.1/bin/proguard.sh";
+  private static final String PROGUARD5_2_1 = "third_party/proguard/proguard5.2.1/bin/proguard.sh";
+  private static final String PROGUARD6_0 = "third_party/proguard/proguard6.0/bin/proguard.sh";
+  private static final String PROGUARD = PROGUARD5_2_1;
 
   public enum DexVm {
     ART_4_0_4_TARGET(Version.V4_0_4, Kind.TARGET),
@@ -947,6 +949,10 @@
     return Paths.get(System.getProperty("java.home"), "bin", "java").toString();
   }
 
+  public static ProcessResult runArtRaw(ArtCommandBuilder builder) throws IOException {
+    return runArtProcessRaw(builder);
+  }
+
   public static ProcessResult runArtRaw(String file, String mainClass)
       throws IOException {
     return runArtRaw(Collections.singletonList(file), mainClass, null);
diff --git a/src/test/java/com/android/tools/r8/debuginfo/PreamblePositionTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/PreamblePositionTestRunner.java
new file mode 100644
index 0000000..14f9f98
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/PreamblePositionTestRunner.java
@@ -0,0 +1,83 @@
+// Copyright (c) 2018, 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.debuginfo;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class PreamblePositionTestRunner {
+
+  private static final String TEST_CLASS = "PreamblePositionTestSource";
+  private static final String TEST_PACKAGE = "com.android.tools.r8.debuginfo";
+
+  @ClassRule public static TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+
+  @Test
+  public void testBothBranchesDefaultConditionals() throws Exception {
+    testBothBranches(false);
+  }
+
+  @Test
+  public void testBothBranchesInvertConditionals() throws Exception {
+    testBothBranches(true);
+  }
+
+  private void testBothBranches(boolean invertConditionals) throws Exception {
+    Path testClassDir = temp.newFolder(TEST_PACKAGE.split(".")).toPath();
+    Path testClassPath = testClassDir.resolve(TEST_CLASS + ".class");
+    Path outputDexPath = temp.newFolder().toPath();
+
+    Files.write(testClassPath, PreamblePositionTestSourceDump.dump());
+
+    ToolHelper.runD8(
+        D8Command.builder()
+            .addProgramFiles(testClassPath)
+            .setOutput(outputDexPath, OutputMode.DexIndexed)
+            .setMode(CompilationMode.RELEASE),
+        options -> {
+          options.testing.invertConditionals = invertConditionals;
+        });
+
+    String fileName = TEST_CLASS + ".java";
+
+    for (boolean testTrueBranch : new boolean[] {false, true}) {
+      ArtCommandBuilder artCommandBuilder = new ArtCommandBuilder();
+      artCommandBuilder.appendClasspath(outputDexPath.resolve("classes.dex").toString());
+      artCommandBuilder.setMainClass(TEST_PACKAGE + "." + TEST_CLASS);
+      if (!testTrueBranch) {
+        artCommandBuilder.appendProgramArgument("1");
+      }
+
+      ProcessResult result = ToolHelper.runArtRaw(artCommandBuilder);
+
+      assertNotEquals(result.exitCode, 0);
+      if (testTrueBranch) {
+        assertTrue(result.stderr.contains("<true-branch-exception>"));
+        // Must have either explicit line = 0 or no line info at all.
+        assertTrue(
+            result.stderr.contains(fileName + ":0")
+                || (result.stderr.contains("at " + TEST_PACKAGE + "." + TEST_CLASS + ".main")
+                    && !result.stderr.contains(fileName + ":")));
+      } else {
+        assertTrue(result.stderr.contains("<false-branch-exception>"));
+        assertTrue(
+            result.stderr.contains(
+                fileName + ":" + PreamblePositionTestSourceDump.FALSE_BRANCH_LINE_NUMBER));
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/PreamblePositionTestSourceDump.java b/src/test/java/com/android/tools/r8/debuginfo/PreamblePositionTestSourceDump.java
new file mode 100644
index 0000000..5ed2a4e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/PreamblePositionTestSourceDump.java
@@ -0,0 +1,106 @@
+// Copyright (c) 2018, 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.debuginfo;
+
+import java.util.*;
+import org.objectweb.asm.*;
+
+/*
+Generated from the source code below, line numbers removed, except for the false branch,
+which is set to FALSE_BRANCH_LINE_NUMBER.
+
+    package com.android.tools.r8.debuginfo;
+
+    public class PreamblePositionTestSource {
+      public static void main(String[] args) {
+        System.err.println("<first-line>");
+        if (args.length == 0) {
+          throw new RuntimeException("<true-branch-exception>");
+        } else {
+          throw new RuntimeException("<false-branch-exception>");
+        }
+      }
+    }
+*/
+
+public class PreamblePositionTestSourceDump implements Opcodes {
+
+  static final int FALSE_BRANCH_LINE_NUMBER = 123;
+
+  public static byte[] dump() throws Exception {
+
+    ClassWriter cw = new ClassWriter(0);
+    FieldVisitor fv;
+    MethodVisitor mv;
+    AnnotationVisitor av0;
+
+    cw.visit(
+        V1_8,
+        ACC_PUBLIC + ACC_SUPER,
+        "com/android/tools/r8/debuginfo/PreamblePositionTestSource",
+        null,
+        "java/lang/Object",
+        null);
+
+    cw.visitSource("PreamblePositionTestSource.java", null);
+
+    {
+      mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+      mv.visitCode();
+      Label l0 = new Label();
+      mv.visitLabel(l0);
+      mv.visitVarInsn(ALOAD, 0);
+      mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+      mv.visitInsn(RETURN);
+      Label l1 = new Label();
+      mv.visitLabel(l1);
+      mv.visitLocalVariable(
+          "this", "Lcom/android/tools/r8/debuginfo/PreamblePositionTestSource;", null, l0, l1, 0);
+      mv.visitMaxs(1, 1);
+      mv.visitEnd();
+    }
+    {
+      mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+      mv.visitCode();
+      Label l0 = new Label();
+      mv.visitLabel(l0);
+      mv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");
+      mv.visitLdcInsn("<first-line>");
+      mv.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      Label l1 = new Label();
+      mv.visitLabel(l1);
+      mv.visitVarInsn(ALOAD, 0);
+      mv.visitInsn(ARRAYLENGTH);
+      Label l2 = new Label();
+      mv.visitJumpInsn(IFNE, l2);
+      Label l3 = new Label();
+      mv.visitLabel(l3);
+      mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+      mv.visitInsn(DUP);
+      mv.visitLdcInsn("<true-branch-exception>");
+      mv.visitMethodInsn(
+          INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V", false);
+      mv.visitInsn(ATHROW);
+      mv.visitLabel(l2);
+      mv.visitLineNumber(FALSE_BRANCH_LINE_NUMBER, l2);
+      mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+      mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+      mv.visitInsn(DUP);
+      mv.visitLdcInsn("<false-branch-exception>");
+      mv.visitMethodInsn(
+          INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V", false);
+      mv.visitInsn(ATHROW);
+      Label l4 = new Label();
+      mv.visitLabel(l4);
+      mv.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l4, 0);
+      mv.visitMaxs(3, 1);
+      mv.visitEnd();
+    }
+    cw.visitEnd();
+
+    return cw.toByteArray();
+  }
+}
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 183c458..00fa060 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -157,6 +157,7 @@
     // Parse from file.
     parser = new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PROGUARD_SPEC_FILE));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> rules = parser.getConfig().getRules();
     assertEquals(24, rules.size());
     assertEquals(1, rules.get(0).getMemberRules().size());
@@ -175,6 +176,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(MULTIPLE_NAME_PATTERNS_FILE));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> rules = parser.getConfig().getRules();
     assertEquals(1, rules.size());
     ProguardConfigurationRule rule = rules.get(0);
@@ -204,6 +206,7 @@
             "  p-.-OtherNameWithDash- -method-(-p.-WithDash-, -package-.-ClassNameWithDash-[]); ",
             "}"));
     parser.parse(createConfigurationForTesting(ImmutableList.of(nonJavaIdentifiers)));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> rules = parser.getConfig().getRules();
     assertEquals(1, rules.size());
     assertEquals(ProguardClassType.CLASS, rules.get(0).getClassType());
@@ -239,6 +242,7 @@
         new ProguardConfigurationParser(dexItemFactory, reporter);
     String dontwarn = "-dontwarn !foobar,*bar";
     parser.parse(createConfigurationForTesting(ImmutableList.of(dontwarn)));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertFalse(
         config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;")));
@@ -257,6 +261,7 @@
     List<String> configuration2 = ImmutableList.of("-dontwarn foo.**", "-dontwarn bar.**");
     for (List<String> configuration : ImmutableList.of(configuration1, configuration2)) {
       parser.parse(createConfigurationForTesting(configuration));
+      verifyParserEndsCleanly();
       ProguardConfiguration config = parser.getConfig();
       assertTrue(
           config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoo/Bar;")));
@@ -274,6 +279,7 @@
         new ProguardConfigurationParser(dexItemFactory, reporter);
     String dontwarnAll = "-dontwarn *";
     parser.parse(createConfigurationForTesting(ImmutableList.of(dontwarnAll)));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(
         config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;")));
@@ -305,6 +311,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ACCESS_FLAGS_FILE));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> rules = parser.getConfig().getRules();
     assertEquals(1, rules.size());
     ProguardConfigurationRule rule = rules.get(0);
@@ -350,6 +357,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(WHY_ARE_YOU_KEEPING_FILE));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> rules = parser.getConfig().getRules();
     assertEquals(1, rules.size());
     ProguardConfigurationRule rule = rules.get(0);
@@ -364,6 +372,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> assumeNoSideEffects = parser.getConfig().getRules();
     assertEquals(1, assumeNoSideEffects.size());
     assumeNoSideEffects.get(0).getMemberRules().forEach(rule -> {
@@ -376,6 +385,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS_WITH_RETURN_VALUE));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> assumeNoSideEffects = parser.getConfig().getRules();
     assertEquals(1, assumeNoSideEffects.size());
     int matches = 0;
@@ -432,6 +442,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ASSUME_VALUES_WITH_RETURN_VALUE));
+    verifyParserEndsCleanly();
     List<ProguardConfigurationRule> assumeValues = parser.getConfig().getRules();
     assertEquals(1, assumeValues.size());
     int matches = 0;
@@ -490,6 +501,7 @@
         new ProguardConfigurationParser(dexItemFactory, reporter);
     String adaptClassStrings = "-adaptclassstrings !foobar,*bar";
     parser.parse(createConfigurationForTesting(ImmutableList.of(adaptClassStrings)));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertFalse(
         config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
@@ -509,6 +521,7 @@
         ImmutableList.of("-adaptclassstrings foo.**", "-adaptclassstrings bar.**");
     for (List<String> configuration : ImmutableList.of(configuration1, configuration2)) {
       parser.parse(createConfigurationForTesting(configuration));
+      verifyParserEndsCleanly();
       ProguardConfiguration config = parser.getConfig();
       assertTrue(
           config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoo/Bar;")));
@@ -526,6 +539,7 @@
         new ProguardConfigurationParser(dexItemFactory, reporter);
     String adaptAll = "-adaptclassstrings *";
     parser.parse(createConfigurationForTesting(ImmutableList.of(adaptAll)));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(
         config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
@@ -542,6 +556,7 @@
         new ProguardConfigurationParser(dexItemFactory, reporter);
     String adaptAll = "-adaptclassstrings";
     parser.parse(createConfigurationForTesting(ImmutableList.of(adaptAll)));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(
         config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
@@ -568,6 +583,7 @@
         + "  @my.annotations.IdentifierNameString *;\n"
         + "}";
     parser.parse(createConfigurationForTesting(ImmutableList.of(config1, config2, config3)));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     List<ProguardConfigurationRule> identifierNameStrings = config.getRules();
     assertEquals(3, identifierNameStrings.size());
@@ -600,6 +616,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(DONT_OBFUSCATE));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertFalse(config.isObfuscating());
   }
@@ -609,6 +626,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_1));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
     assertNotNull(config.getPackagePrefix());
@@ -620,6 +638,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_2));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
     assertNotNull(config.getPackagePrefix());
@@ -631,6 +650,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_3));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertEquals(PackageObfuscationMode.FLATTEN, config.getPackageObfuscationMode());
     assertNotNull(config.getPackagePrefix());
@@ -642,6 +662,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_4));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertEquals(PackageObfuscationMode.FLATTEN, config.getPackageObfuscationMode());
     assertNotNull(config.getPackagePrefix());
@@ -649,11 +670,13 @@
   }
 
   @Test
-  public void flattenPackageHierarchyCannotOverrideRepackageClasses()
-      throws Exception {
+  public void flattenPackageHierarchyCannotOverrideRepackageClasses() throws Exception {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
-    parser.parse(Paths.get(PACKAGE_OBFUSCATION_5));
+    Path path = Paths.get(PACKAGE_OBFUSCATION_5);
+    parser.parse(path);
+    checkDiagnostic(handler.warnings, path, 6, 1,
+        "repackageclasses", "overrides", "flattenpackagehierarchy");
     ProguardConfiguration config = parser.getConfig();
     assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
     assertNotNull(config.getPackagePrefix());
@@ -661,11 +684,13 @@
   }
 
   @Test
-  public void repackageClassesOverridesFlattenPackageHierarchy()
-      throws Exception {
+  public void repackageClassesOverridesFlattenPackageHierarchy() throws Exception {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
-    parser.parse(Paths.get(PACKAGE_OBFUSCATION_6));
+    Path path = Paths.get(PACKAGE_OBFUSCATION_6);
+    parser.parse(path);
+    checkDiagnostic(handler.warnings, path, 6, 1,
+        "repackageclasses", "overrides", "flattenpackagehierarchy");
     ProguardConfiguration config = parser.getConfig();
     assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode());
     assertNotNull(config.getPackagePrefix());
@@ -677,6 +702,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(APPLY_MAPPING));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.hasApplyMappingFile());
   }
@@ -696,8 +722,10 @@
 
   @Test
   public void parseIncluding() throws Exception {
-    new ProguardConfigurationParser(new DexItemFactory(), reporter)
-        .parse(Paths.get(INCLUDING));
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(Paths.get(INCLUDING));
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -743,11 +771,10 @@
           new ProguardConfigurationParser(new DexItemFactory(), reporter);
       parser.parse(createConfigurationForTesting(
           Collections.singletonList("-injars abc.jar(*.zip;*.class)")));
+      fail();
     } catch (AbortException e) {
       assertEquals(1, handler.errors.size());
-      return;
     }
-    fail();
   }
 
   @Test
@@ -755,6 +782,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(SEEDS));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.isPrintSeeds());
     assertNull(config.getSeedFile());
@@ -765,6 +793,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(SEEDS_2));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.isPrintSeeds());
     assertNotNull(config.getSeedFile());
@@ -775,6 +804,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(VERBOSE));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.isVerbose());
   }
@@ -784,6 +814,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(KEEPDIRECTORIES));
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -791,6 +822,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(DONT_SHRINK));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertFalse(config.isShrinking());
   }
@@ -800,6 +832,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES));
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -807,6 +840,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS));
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -815,8 +849,7 @@
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     Path source = Paths.get(IDENTIFIER_NAME_STRING);
     parser.parse(source);
-    assertEquals(0, handler.infos.size());
-    assertEquals(0, handler.warnings.size());
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -824,6 +857,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(OVERLOAD_AGGRESIVELY));
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -832,21 +866,30 @@
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(DONT_OPTIMIZE));
     ProguardConfiguration config = parser.getConfig();
+    verifyParserEndsCleanly();
+    assertFalse(config.isOptimizing());
   }
 
   @Test
   public void parseDontOptimizeOverridesPasses() throws Exception {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
-    parser.parse(Paths.get(DONT_OPTIMIZE_OVERRIDES_PASSES));
+    Path path = Paths.get(DONT_OPTIMIZE_OVERRIDES_PASSES);
+    parser.parse(path);
+    checkDiagnostic(handler.warnings, path, 7, 1,
+        "Ignoring", "-optimizationpasses");
     ProguardConfiguration config = parser.getConfig();
+    assertFalse(config.isOptimizing());
   }
 
   @Test
   public void parseOptimizationPasses() throws Exception {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
-    parser.parse(Paths.get(OPTIMIZATION_PASSES));
+    Path path = Paths.get(OPTIMIZATION_PASSES);
+    parser.parse(path);
+    checkDiagnostic(handler.warnings, path, 5, 1,
+        "Ignoring", "-optimizationpasses");
     ProguardConfiguration config = parser.getConfig();
   }
 
@@ -882,6 +925,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PARSE_AND_SKIP_SINGLE_ARGUMENT));
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -889,6 +933,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PRINT_USAGE));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.isPrintUsage());
     assertNull(config.getPrintUsageFile());
@@ -899,6 +944,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PRINT_USAGE_TO_FILE));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.isPrintUsage());
     assertNotNull(config.getPrintUsageFile());
@@ -909,6 +955,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(TARGET));
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -938,6 +985,7 @@
         "-laststageoutput /some/file/name  "
     );
     parser.parse(proguardConfig);
+    verifyParserEndsCleanly();
   }
 
   @Test
@@ -947,6 +995,7 @@
     String config1 = "-renamesourcefileattribute PG\n";
     String config2 = "-keepattributes SourceFile,SourceDir\n";
     parser.parse(createConfigurationForTesting(ImmutableList.of(config1, config2)));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertEquals("PG", config.getRenameSourceFileAttribute());
     assertTrue(config.getKeepAttributes().sourceFile);
@@ -969,6 +1018,7 @@
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(createConfigurationForTesting(ImmutableList.of(config)));
+    verifyParserEndsCleanly();
     assertEquals(
         ProguardKeepAttributes.fromPatterns(expected),
         parser.getConfigRawForTesting().getKeepAttributes());
@@ -1011,6 +1061,7 @@
     parser.parse(createConfigurationForTesting(ImmutableList.of(
         "-useuniqueclassmembernames"
     )));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.isUseUniqueClassMemberNames());
   }
@@ -1039,6 +1090,7 @@
         "-keepparameternames",
         "-dontobfuscate"
     )));
+    verifyParserEndsCleanly();
     ProguardConfiguration config = parser.getConfig();
     assertTrue(config.isKeepParameterNames());
 
@@ -1046,9 +1098,11 @@
     parser.parse(createConfigurationForTesting(ImmutableList.of(
         "-keepparameternames"
     )));
+    verifyParserEndsCleanly();
     parser.parse(createConfigurationForTesting(ImmutableList.of(
         "-dontobfuscate"
     )));
+    verifyParserEndsCleanly();
     config = parser.getConfig();
     assertTrue(config.isKeepParameterNames());
   }
@@ -1059,12 +1113,11 @@
       ProguardConfigurationParser parser =
           new ProguardConfigurationParser(new DexItemFactory(), reporter);
       parser.parse(createConfigurationForTesting(Collections.singletonList("-")));
+      fail();
     } catch (AbortException e) {
       assertEquals(1, handler.errors.size());
       assertTrue(handler.errors.get(0).getDiagnosticMessage().contains("-"));
-      return;
     }
-    fail();
   }
 
   @Test
@@ -1073,12 +1126,160 @@
       ProguardConfigurationParser parser =
           new ProguardConfigurationParser(new DexItemFactory(), reporter);
       parser.parse(createConfigurationForTesting(Collections.singletonList("--no-locals")));
+      fail();
     } catch (AbortException e) {
+
       assertEquals(1, handler.errors.size());
       assertTrue(handler.errors.get(0).getDiagnosticMessage().contains("--no-locals"));
-      return;
     }
-    fail();
+  }
+
+  @Test
+  public void parse_if() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-if   class **$$ModuleAdapter",
+        "-keep class A",
+        "-if   class **$$InjectAdapter",
+        "-keep class B",
+        "-if   class **$$StaticInjection",
+        "-keep class C",
+        "-keepnames class dagger.Lazy"
+    );
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    assertEquals(3, handler.warnings.size());
+    for (int i = 0; i < 3; i++) {
+      assertTrue(handler.warnings.get(i).getDiagnosticMessage().contains("Ignoring option: -if"));
+    }
+  }
+
+  @Test
+  public void parse_if_if() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-if   class **$$ModuleAdapter",
+        "-if   class **$$InjectAdapter"
+    );
+    try {
+      ProguardConfigurationParser parser =
+          new ProguardConfigurationParser(new DexItemFactory(), reporter);
+      parser.parse(proguardConfig);
+      fail();
+    } catch (AbortException e) {
+      checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+          "without", "subsequent", "keep");
+    }
+  }
+
+  @Test
+  public void parse_if_end() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-if   class **$$ModuleAdapter"
+    );
+    try {
+      ProguardConfigurationParser parser =
+          new ProguardConfigurationParser(new DexItemFactory(), reporter);
+      parser.parse(proguardConfig);
+      fail();
+    } catch (AbortException e) {
+      checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+          "without", "subsequent", "keep");
+    }
+  }
+
+  @Test
+  public void parse_assumenoexternalsideeffects() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-assumenoexternalsideeffects class java.lang.StringBuilder {",
+        "  public java.lang.StringBuilder();",
+        "  public java.lang.StringBuilder(int);",
+        "  public java.lang.StringBuilder(java.lang.String);",
+        "  public java.lang.StringBuilder append(java.lang.Object);",
+        "  public java.lang.StringBuilder append(java.lang.String);",
+        "  public java.lang.StringBuilder append(java.lang.StringBuffer);",
+        "  public java.lang.StringBuilder append(char[]);",
+        "  public java.lang.StringBuilder append(char[], int, int);",
+        "  public java.lang.StringBuilder append(boolean);",
+        "  public java.lang.StringBuilder append(char);",
+        "  public java.lang.StringBuilder append(int);",
+        "  public java.lang.StringBuilder append(long);",
+        "  public java.lang.StringBuilder append(float);",
+        "  public java.lang.StringBuilder append(double);",
+        "  public java.lang.String toString();",
+        "}"
+    );
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    checkDiagnostic(handler.warnings, proguardConfig, 1, 1,
+        "Ignoring", "-assumenoexternalsideeffects");
+  }
+
+  @Test
+  public void parse_assumenoescapingparameters() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-assumenoescapingparameters class java.lang.System {",
+        "  public static void arraycopy(java.lang.Object, int, java.lang.Object, int, int);",
+        "}"
+    );
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    checkDiagnostic(handler.warnings, proguardConfig, 1, 1,
+        "Ignoring", "-assumenoescapingparameters");
+  }
+
+  @Test
+  public void parse_assumenoexternalreturnvalues() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-assumenoexternalreturnvalues class java.lang.StringBuilder {",
+        "  public java.lang.StringBuilder append(java.lang.Object);",
+        "  public java.lang.StringBuilder append(java.lang.String);",
+        "  public java.lang.StringBuilder append(java.lang.StringBuffer);",
+        "  public java.lang.StringBuilder append(char[]);",
+        "  public java.lang.StringBuilder append(char[], int, int);",
+        "  public java.lang.StringBuilder append(boolean);",
+        "  public java.lang.StringBuilder append(char);",
+        "  public java.lang.StringBuilder append(int);",
+        "  public java.lang.StringBuilder append(long);",
+        "  public java.lang.StringBuilder append(float);",
+        "  public java.lang.StringBuilder append(double);",
+        "}"
+    );
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    checkDiagnostic(handler.warnings, proguardConfig, 1, 1,
+        "Ignoring", "-assumenoexternalreturnvalues");
+  }
+
+  @Test
+  public void parse_android() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-android"
+    );
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    verifyParserEndsCleanly();
+  }
+
+  @Test
+  public void parse_addconfigurationdebugging() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-addconfigurationdebugging"
+    );
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    checkDiagnostic(handler.warnings, proguardConfig, 1, 1,
+        "Ignoring", "-addconfigurationdebugging");
+  }
+
+  private void verifyParserEndsCleanly() {
+    assertEquals(0, handler.infos.size());
+    assertEquals(0, handler.warnings.size());
+    assertEquals(0, handler.errors.size());
   }
 
   private Diagnostic checkDiagnostic(List<Diagnostic> diagnostics, Path path, int lineStart,
@@ -1094,8 +1295,8 @@
     }
     assertEquals(lineStart, position.getLine());
     assertEquals(columnStart, position.getColumn());
-    for (String part:messageParts) {
-      assertTrue(diagnostic.getDiagnosticMessage()+ "doesn't contain \"" + part + "\"",
+    for (String part : messageParts) {
+      assertTrue(diagnostic.getDiagnosticMessage()+ " doesn't contain \"" + part + "\"",
           diagnostic.getDiagnosticMessage().contains(part));
     }
     return diagnostic;
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
index 085e46c..cfbfa84 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -296,9 +296,12 @@
           ImmutableList.of(mainClass, forNameClass1, forNameClass2)),
           proguardedJar, proguardConfigFile);
       Set<String> classesAfterProguard = readClassesInJar(proguardedJar);
+      assertEquals(3, classesAfterProguard.size());
       assertTrue(classesAfterProguard.contains(mainClass.getCanonicalName()));
-      assertTrue(classesAfterProguard.contains(forNameClass1.getCanonicalName()));
-      assertTrue(classesAfterProguard.contains(forNameClass2.getCanonicalName()));
+      if (!allowObfuscation) {
+        assertTrue(classesAfterProguard.contains(forNameClass1.getCanonicalName()));
+        assertTrue(classesAfterProguard.contains(forNameClass2.getCanonicalName()));
+      }
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
index 16545bd..ca3fd2a 100644
--- a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
@@ -11,18 +11,15 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.DexInspector;
 import com.google.common.collect.ImmutableList;
-import java.io.IOException;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 import org.junit.Test;
 
 public class IncludeDescriptorClassesTest extends TestBase {
+  // Actually running Proguard should only be during development.
+  private final boolean RUN_PROGUARD = false;
 
   private class Result {
     final DexInspector inspector;
@@ -75,8 +72,8 @@
 
     Set<String> classesAfterProguard = null;
     // Actually running Proguard should only be during development.
-    if (false) {
-      Path proguardedJar = temp.newFile("proguarded.jar").toPath();
+    if (RUN_PROGUARD) {
+      Path proguardedJar = temp.newFolder().toPath().resolve("proguarded.jar");
       ToolHelper.runProguard(jarTestClasses(classes), proguardedJar, proguardConfig);
       classesAfterProguard = readClassesInJar(proguardedJar);
     }
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index 64ea9b4..5088aeb 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.code.ConstWideHigh16;
 import com.android.tools.r8.code.DivInt;
 import com.android.tools.r8.code.DivInt2Addr;
+import com.android.tools.r8.code.Goto;
 import com.android.tools.r8.code.InvokeStatic;
 import com.android.tools.r8.code.InvokeVirtual;
 import com.android.tools.r8.code.MoveResult;
@@ -1244,7 +1245,7 @@
     assertTrue(code.instructions[1] instanceof InvokeStatic);
     assertTrue(code.instructions[2] instanceof MoveResult);
     assertTrue(code.instructions[3] instanceof DivInt2Addr);
-    assertTrue(code.instructions[4] instanceof Return);
+    assertTrue(code.instructions[4] instanceof Goto);
     assertTrue(code.instructions[5] instanceof Const4);
     assertTrue(code.instructions[6] instanceof Return);
     InvokeStatic invoke = (InvokeStatic) code.instructions[1];
diff --git a/third_party/proguard/README.google b/third_party/proguard/README.google
index 4dc91ad..4f85601 100644
--- a/third_party/proguard/README.google
+++ b/third_party/proguard/README.google
@@ -1,7 +1,8 @@
 URL: https://sourceforge.net/projects/proguard/files/proguard/5.2/
-Version: 5.2.1
+URL: https://sourceforge.net/projects/proguard/files/proguard/6.0/
+Version: 5.2.1, 6.0
 License: GPL
-License File: docs/license.html
+License File: proguard5.2.1/docs/license.html, proguard6.0/docs/license.html
 
 Description:
 ProGuard Java Optimizer and Obfuscator
diff --git a/third_party/proguard/proguard6.0.tar.gz.sha1 b/third_party/proguard/proguard6.0.tar.gz.sha1
new file mode 100644
index 0000000..4596bc8
--- /dev/null
+++ b/third_party/proguard/proguard6.0.tar.gz.sha1
@@ -0,0 +1 @@
+57d0702f38196c81ff506d2e34a4a5569c3af583
\ No newline at end of file