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