Merge "Make Shrinker-specific utils instance methods."
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 297d6df..34a3a93 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.Reporter;
import java.nio.file.Path;
@@ -36,7 +35,7 @@
programConsumer = null;
mode = null;
minApiLevel = 0;
- reporter = new Reporter(new DefaultDiagnosticsHandler());
+ reporter = new Reporter();
enableDesugaring = true;
optimizeMultidexForLinearAlloc = false;
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 964f699..2441034 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -38,20 +37,20 @@
}
}
- private static class DefaultD8DiagnosticsHandler extends DefaultDiagnosticsHandler {
+ private static class DefaultD8DiagnosticsHandler implements DiagnosticsHandler {
@Override
public void error(Diagnostic error) {
if (error instanceof DexFileOverflowDiagnostic) {
DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error;
if (!overflowDiagnostic.hasMainDexSpecification()) {
- super.error(
+ DiagnosticsHandler.super.error(
new StringDiagnostic(
overflowDiagnostic.getDiagnosticMessage() + ". Try supplying a main-dex list"));
return;
}
}
- super.error(error);
+ DiagnosticsHandler.super.error(error);
}
}
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java b/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
index 2d06da8..ec7bc53 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.shaking.ProguardConfigurationSourceFile;
import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -199,7 +198,7 @@
this.factory = new DexItemFactory();
this.mainDexKeepRules = ImmutableList.of();
this.mainDexListConsumer = null;
- this.reporter = new Reporter(new DefaultDiagnosticsHandler());
+ this.reporter = new Reporter();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 78a9d3f..96e1e99 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.shaking.ProguardConfigurationSourceFile;
import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -58,21 +57,21 @@
@Keep
public static class Builder extends BaseCompilerCommand.Builder<R8Command, Builder> {
- private static class DefaultR8DiagnosticsHandler extends DefaultDiagnosticsHandler {
+ private static class DefaultR8DiagnosticsHandler implements DiagnosticsHandler {
@Override
public void error(Diagnostic error) {
if (error instanceof DexFileOverflowDiagnostic) {
DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error;
if (!overflowDiagnostic.hasMainDexSpecification()) {
- super.error(
+ DiagnosticsHandler.super.error(
new StringDiagnostic(
overflowDiagnostic.getDiagnosticMessage()
+ ". Try supplying a main-dex list or main-dex rules"));
return;
}
}
- super.error(error);
+ DiagnosticsHandler.super.error(error);
}
}
diff --git a/src/main/java/com/android/tools/r8/ReadKeepFile.java b/src/main/java/com/android/tools/r8/ReadKeepFile.java
index 07d5044..c953c8d 100644
--- a/src/main/java/com/android/tools/r8/ReadKeepFile.java
+++ b/src/main/java/com/android/tools/r8/ReadKeepFile.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.Timing;
import java.nio.file.Paths;
@@ -22,8 +21,7 @@
private void readProguardKeepFile(String fileName) {
System.out.println(" - reading " + fileName);
timing.begin("Reading " + fileName);
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()))
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter())
.parse(Paths.get(fileName));
timing.end();
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index d762646..657e029 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -59,7 +59,6 @@
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.Pair;
import com.google.common.io.ByteStreams;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
@@ -97,8 +96,9 @@
}
private static DexSection[] parseMapFrom(DexReader dexReader) {
- DexParser dexParser = new DexParser(dexReader,
- ClassKind.PROGRAM, new DexItemFactory(), new DefaultDiagnosticsHandler());
+ DexParser dexParser =
+ new DexParser(
+ dexReader, ClassKind.PROGRAM, new DexItemFactory(), new DiagnosticsHandler() {});
return dexParser.dexSections;
}
diff --git a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java b/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
index 321482e..f83012f 100644
--- a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
+++ b/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.Keep;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.AbortException;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.FeatureClassMapping;
@@ -87,7 +86,7 @@
@Keep
public static final class Options {
- private final DiagnosticsHandler diagnosticsHandler = new DefaultDiagnosticsHandler();
+ private final DiagnosticsHandler diagnosticsHandler = new DiagnosticsHandler() {};
private List<String> inputArchives = new ArrayList<>();
private List<FeatureJar> featureJars = new ArrayList<>();
private List<String> baseJars = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 400e5ba..0f0b5e5 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import static org.objectweb.asm.ClassReader.SKIP_CODE;
+import static org.objectweb.asm.ClassReader.SKIP_DEBUG;
import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
import static org.objectweb.asm.Opcodes.ACC_DEPRECATED;
import static org.objectweb.asm.Opcodes.ASM6;
@@ -27,6 +28,7 @@
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.FieldSignatureEquivalence;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
@@ -93,9 +95,18 @@
input.reset();
ClassReader reader = new ClassReader(input);
+
+ int parsingOptions = SKIP_FRAMES | SKIP_CODE;
+
+ // If the source-file and source-debug-extension attributes are not kept we can skip all debug
+ // related attributes when parsing the class structure.
+ ProguardKeepAttributes keep = application.options.proguardConfiguration.getKeepAttributes();
+ if (!keep.sourceFile && !keep.sourceDebugExtension) {
+ parsingOptions |= SKIP_DEBUG;
+ }
reader.accept(
new CreateDexClassVisitor(origin, classKind, reader.b, application, classConsumer),
- SKIP_FRAMES | SKIP_CODE);
+ parsingOptions);
}
private static int cleanAccessFlags(int access) {
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index b978408..0668d05 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.io.PrintWriter;
@@ -163,7 +164,7 @@
InternalOptions options,
ValueNumberGenerator generator,
Position callerPosition) {
- if (!options.debug || options.testing.removeLocalsTable) {
+ if (!options.debug || !options.proguardConfiguration.getKeepAttributes().localVariableTable) {
node.localVariables.clear();
}
JarSourceCode source =
@@ -241,9 +242,16 @@
}
private void parseCode(ReparseContext context, boolean useJsrInliner) {
+ // If the keep attributes do not specify keeping LocalVariableTable, LocalVariableTypeTable or
+ // LineNumberTable, then we can skip parsing all the debug related attributes during code read.
+ int parsingOptions = ClassReader.SKIP_FRAMES;
+ ProguardKeepAttributes keep = application.options.proguardConfiguration.getKeepAttributes();
+ if (!keep.localVariableTable && !keep.localVariableTypeTable && !keep.lineNumberTable) {
+ parsingOptions |= ClassReader.SKIP_DEBUG;
+ }
SecondVisitor classVisitor = new SecondVisitor(createCodeLocator(context), useJsrInliner);
try {
- new ClassReader(context.classCache).accept(classVisitor, ClassReader.SKIP_FRAMES);
+ new ClassReader(context.classCache).accept(classVisitor, parsingOptions);
} catch (Exception exception) {
throw new CompilationError(
"Unable to parse method `" + method.toSourceString() + "`", exception);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index c773eff..d3b57cd 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -46,10 +46,12 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.VerticalClassMerger.VerticallyMergedClasses;
import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class LensCodeRewriter {
@@ -69,18 +71,24 @@
this.options = options;
}
- private Value makeOutValue(Instruction insn, IRCode code) {
+ private Value makeOutValue(
+ Instruction insn,
+ IRCode code,
+ ImmutableSet.Builder<Value> collector) {
if (insn.outValue() == null) {
return null;
} else {
- return code.createValue(insn.outValue().getTypeLattice(), insn.getLocalInfo());
+ Value newValue = code.createValue(insn.outValue().getTypeLattice(), insn.getLocalInfo());
+ collector.add(newValue);
+ return newValue;
}
}
/**
* Replace type appearances, invoke targets and field accesses with actual definitions.
*/
- public void rewrite(IRCode code, DexEncodedMethod method) {
+ public Set<Value> rewrite(IRCode code, DexEncodedMethod method) {
+ ImmutableSet.Builder<Value> valueCollector = ImmutableSet.builder();
ListIterator<BasicBlock> blocks = code.blocks.listIterator();
while (blocks.hasNext()) {
BasicBlock block = blocks.next();
@@ -118,10 +126,7 @@
handle, method, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY);
if (newHandle != handle) {
ConstMethodHandle newInstruction =
- new ConstMethodHandle(
- code.createValue(
- current.outValue().getTypeLattice(), current.getLocalInfo()),
- newHandle);
+ new ConstMethodHandle(makeOutValue(current, code, valueCollector), newHandle);
iterator.replaceCurrentInstruction(newInstruction);
}
} else if (current.isInvokeMethod()) {
@@ -145,8 +150,7 @@
// Fix up the return type if needed.
if (actualTarget.proto.returnType != invokedMethod.proto.returnType
&& newInvoke.outValue() != null) {
- Value newValue = code.createValue(
- newInvoke.outValue().getTypeLattice(), invoke.getLocalInfo());
+ Value newValue = makeOutValue(newInvoke, code, valueCollector);
newInvoke.outValue().replaceUsers(newValue);
CheckCast cast =
new CheckCast(
@@ -204,60 +208,66 @@
CheckCast checkCast = current.asCheckCast();
DexType newType = graphLense.lookupType(checkCast.getType());
if (newType != checkCast.getType()) {
- CheckCast newCheckCast =
- new CheckCast(makeOutValue(checkCast, code), checkCast.object(), newType);
+ CheckCast newCheckCast = new CheckCast(
+ makeOutValue(checkCast, code, valueCollector), checkCast.object(), newType);
iterator.replaceCurrentInstruction(newCheckCast);
}
} else if (current.isConstClass()) {
ConstClass constClass = current.asConstClass();
DexType newType = graphLense.lookupType(constClass.getValue());
if (newType != constClass.getValue()) {
- ConstClass newConstClass = new ConstClass(makeOutValue(constClass, code), newType);
+ ConstClass newConstClass = new ConstClass(
+ makeOutValue(constClass, code, valueCollector), newType);
iterator.replaceCurrentInstruction(newConstClass);
}
} else if (current.isInstanceOf()) {
InstanceOf instanceOf = current.asInstanceOf();
DexType newType = graphLense.lookupType(instanceOf.type());
if (newType != instanceOf.type()) {
- InstanceOf newInstanceOf = new InstanceOf(makeOutValue(instanceOf, code),
- instanceOf.value(), newType);
+ InstanceOf newInstanceOf = new InstanceOf(
+ makeOutValue(instanceOf, code, valueCollector), instanceOf.value(), newType);
iterator.replaceCurrentInstruction(newInstanceOf);
}
} else if (current.isInvokeMultiNewArray()) {
InvokeMultiNewArray multiNewArray = current.asInvokeMultiNewArray();
DexType newType = graphLense.lookupType(multiNewArray.getArrayType());
if (newType != multiNewArray.getArrayType()) {
- InvokeMultiNewArray newMultiNewArray = new InvokeMultiNewArray(
- newType, makeOutValue(multiNewArray, code), multiNewArray.inValues());
+ InvokeMultiNewArray newMultiNewArray =
+ new InvokeMultiNewArray(
+ newType,
+ makeOutValue(multiNewArray, code, valueCollector),
+ multiNewArray.inValues());
iterator.replaceCurrentInstruction(newMultiNewArray);
}
} else if (current.isInvokeNewArray()) {
InvokeNewArray newArray = current.asInvokeNewArray();
DexType newType = graphLense.lookupType(newArray.getArrayType());
if (newType != newArray.getArrayType()) {
- InvokeNewArray newNewArray = new InvokeNewArray(newType, makeOutValue(newArray, code),
- newArray.inValues());
+ InvokeNewArray newNewArray = new InvokeNewArray(
+ newType, makeOutValue(newArray, code, valueCollector), newArray.inValues());
iterator.replaceCurrentInstruction(newNewArray);
}
} else if (current.isNewArrayEmpty()) {
NewArrayEmpty newArrayEmpty = current.asNewArrayEmpty();
DexType newType = graphLense.lookupType(newArrayEmpty.type);
if (newType != newArrayEmpty.type) {
- NewArrayEmpty newNewArray = new NewArrayEmpty(makeOutValue(newArrayEmpty, code),
- newArrayEmpty.size(), newType);
+ NewArrayEmpty newNewArray = new NewArrayEmpty(
+ makeOutValue(newArrayEmpty, code, valueCollector), newArrayEmpty.size(), newType);
iterator.replaceCurrentInstruction(newNewArray);
}
} else if (current.isNewInstance()) {
NewInstance newInstance= current.asNewInstance();
DexType newClazz = graphLense.lookupType(newInstance.clazz);
if (newClazz != newInstance.clazz) {
- NewInstance newNewInstance = new NewInstance(newClazz, makeOutValue(newInstance, code));
+ NewInstance newNewInstance = new NewInstance(
+ newClazz, makeOutValue(newInstance, code, valueCollector));
iterator.replaceCurrentInstruction(newNewInstance);
}
}
}
}
assert code.isConsistentSSA();
+ return valueCollector.build();
}
// If the given invoke is on the form "invoke-direct A.<init>, v0, ..." and the definition of
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java
index fe31b14..49f99dc 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java
@@ -16,6 +16,9 @@
public static final String ENCLOSING_METHOD = "EnclosingMethod";
public static final String SIGNATURE = "Signature";
public static final String EXCEPTIONS = "Exceptions";
+ public static final String LINE_NUMBER_TABLE = "LineNumberTable";
+ public static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
+ public static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
public static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
public static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
public static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
@@ -36,6 +39,9 @@
public boolean enclosingMethod = false;
public boolean signature = false;
public boolean exceptions = false;
+ public boolean lineNumberTable = false;
+ public boolean localVariableTable = false;
+ public boolean localVariableTypeTable = false;
public boolean sourceDebugExtension = false;
public boolean runtimeVisibleAnnotations = false;
public boolean runtimeInvisibleAnnotations = false;
@@ -108,6 +114,9 @@
innerClasses = update(innerClasses, INNER_CLASSES, patterns);
enclosingMethod = update(enclosingMethod, ENCLOSING_METHOD, patterns);
signature = update(signature, SIGNATURE, patterns);
+ lineNumberTable = update(lineNumberTable, LINE_NUMBER_TABLE, patterns);
+ localVariableTable = update(localVariableTable, LOCAL_VARIABLE_TABLE, patterns);
+ localVariableTypeTable = update(localVariableTypeTable, LOCAL_VARIABLE_TYPE_TABLE, patterns);
exceptions = update(exceptions, EXCEPTIONS, patterns);
sourceDebugExtension = update(sourceDebugExtension, SOURCE_DEBUG_EXTENSION, patterns);
runtimeVisibleAnnotations = update(runtimeVisibleAnnotations, RUNTIME_VISIBLE_ANNOTATIONS,
@@ -146,6 +155,18 @@
throw new CompilationError("Attribute Signature requires InnerClasses attribute. Check "
+ "-keepattributes directive.");
}
+ if (forceProguardCompatibility && localVariableTable && !lineNumberTable) {
+ // If locals are kept, assume line numbers should be kept too.
+ lineNumberTable = true;
+ compatibility.addKeepAttributePatterns(
+ ImmutableList.of(ProguardKeepAttributes.LINE_NUMBER_TABLE));
+ }
+ if (localVariableTable && !lineNumberTable) {
+ throw new CompilationError(
+ "Attribute " + LOCAL_VARIABLE_TABLE
+ + " requires " + LINE_NUMBER_TABLE
+ + ". Check -keepattributes directive.");
+ }
}
@Override
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index f087295..a4f55c3 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -79,7 +79,7 @@
}
static Reporter defaultReporter() {
- return new Reporter(new DefaultDiagnosticsHandler());
+ return new Reporter();
}
/**
diff --git a/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java b/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java
deleted file mode 100644
index 68c2840..0000000
--- a/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.utils;
-
-import com.android.tools.r8.DiagnosticsHandler;
-
-public class DefaultDiagnosticsHandler implements DiagnosticsHandler {
-}
diff --git a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
index 44cfc89..dcf521d 100644
--- a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
+++ b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
@@ -85,7 +85,7 @@
}
public static FeatureClassMapping fromSpecification(Path file) throws FeatureMappingException {
- return fromSpecification(file, new DefaultDiagnosticsHandler());
+ return fromSpecification(file, new DiagnosticsHandler() {});
}
public static FeatureClassMapping fromSpecification(Path file, DiagnosticsHandler reporter)
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index e0e4227..828a463 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -57,7 +57,7 @@
// Constructor for testing and/or other utilities.
public InternalOptions() {
- reporter = new Reporter(new DefaultDiagnosticsHandler());
+ reporter = new Reporter();
itemFactory = new DexItemFactory();
proguardConfiguration = ProguardConfiguration.defaultConfiguration(itemFactory, reporter);
}
@@ -462,7 +462,6 @@
public boolean nondeterministicCycleElimination = false;
public Set<Inliner.Reason> validInliningReasons = null;
public boolean suppressExperimentalCfBackendWarning = false;
- public boolean removeLocalsTable = false;
}
public boolean canUseInvokePolymorphicOnVarHandle() {
diff --git a/src/main/java/com/android/tools/r8/utils/Reporter.java b/src/main/java/com/android/tools/r8/utils/Reporter.java
index 37f57da..5a1bd06 100644
--- a/src/main/java/com/android/tools/r8/utils/Reporter.java
+++ b/src/main/java/com/android/tools/r8/utils/Reporter.java
@@ -20,6 +20,10 @@
private Diagnostic lastError;
private final Collection<Throwable> suppressedExceptions = new ArrayList<>();
+ public Reporter() {
+ this(new DiagnosticsHandler() {});
+ }
+
public Reporter(DiagnosticsHandler clientHandler) {
this.clientHandler = clientHandler;
}
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 97be613..5e70808 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -2,6 +2,9 @@
# 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.
+# Keep line numbers to ensure method mappings in the map file.
+-keepattributes LineNumberTable
+
# Keep the application entry point. Get rid of everything that is not
# reachable from there.
-keep public class classmerging.Test {
@@ -57,6 +60,3 @@
}
-printmapping
-
-# TODO(herhut): Consider supporting merging of inner-class attributes.
-# -keepattributes *
\ No newline at end of file
diff --git a/src/test/examples/shaking1/keep-rules.txt b/src/test/examples/shaking1/keep-rules.txt
index 66cf1c6..82786d5 100644
--- a/src/test/examples/shaking1/keep-rules.txt
+++ b/src/test/examples/shaking1/keep-rules.txt
@@ -2,6 +2,8 @@
# 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.
+-keepattributes LineNumberTable
+
# Keep the application entry point. Get rid of everything that is not
# reachable from there.
-keep public class shaking1.Shaking {
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index fa35d0d..6f93df4 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.SmaliWriter;
@@ -711,7 +710,7 @@
protected ProcessResult runOnVMRaw(AndroidApp app, Class<?> mainClass, Backend backend)
throws IOException {
- return runOnVMRaw(app, mainClass.getCanonicalName(), backend);
+ return runOnVMRaw(app, mainClass.getTypeName(), backend);
}
protected ProcessResult runOnVMRaw(AndroidApp app, String mainClass, Backend backend)
@@ -830,13 +829,6 @@
.map(kind::cast);
}
- protected Stream<CfInstruction> filterInstructionKind(
- CfCode code, Class<? extends CfInstruction> kind) {
- return code.getInstructions().stream()
- .filter(kind::isInstance)
- .map(kind::cast);
- }
-
public enum MinifyMode {
NONE,
JAVA,
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index f5eaa25..6dde9ed 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
@@ -808,7 +807,7 @@
public static ProguardConfiguration loadProguardConfiguration(
DexItemFactory factory, List<Path> configPaths)
throws IOException, ProguardRuleParserException {
- Reporter reporter = new Reporter(new DefaultDiagnosticsHandler());
+ Reporter reporter = new Reporter();
if (configPaths.isEmpty()) {
return ProguardConfiguration.defaultConfiguration(factory, reporter);
}
@@ -949,7 +948,7 @@
}
public static ProcessResult runJava(Class clazz) throws Exception {
- String main = clazz.getCanonicalName();
+ String main = clazz.getTypeName();
Path path = getClassPathForTests();
return runJava(path, main);
}
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
index 6333638..b85b15b 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Reporter;
import java.nio.file.Path;
@@ -184,7 +183,7 @@
if (frontend == Frontend.CF && compilationMode == CompilationMode.DEBUG) {
// TODO(b/79725635): Investigate why these tests fail on the buildbot.
// Use a Reporter to extract origin info to standard error.
- new Reporter(new DefaultDiagnosticsHandler()).error(e);
+ new Reporter().error(e);
// Print the stack trace since this is not always printed by JUnit.
e.printStackTrace();
Assume.assumeNoException(
diff --git a/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java b/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java
index 308e8d7..e0b953a 100644
--- a/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java
@@ -27,7 +27,7 @@
DebugTestConfig d8NoLocals = new D8DebugTestConfig().compileAndAdd(
temp,
Collections.singletonList(ToolHelper.getClassFileForTestClass(CLASS)),
- options -> options.testing.removeLocalsTable = true);
+ options -> options.proguardConfiguration.getKeepAttributes().localVariableTable = false);
new DebugStreamComparator()
.add("CF", streamDebugTest(cf, NAME, NO_FILTER))
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index a518a36..7e3c10a 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
@@ -136,8 +135,7 @@
DexApplication application = builder.build();
CollectInfoConsumer consumer = new CollectInfoConsumer();
- InternalOptions options = new InternalOptions(dexItemFactory,
- new Reporter(new DefaultDiagnosticsHandler()));
+ InternalOptions options = new InternalOptions(dexItemFactory, new Reporter());
options.programConsumer = consumer;
ApplicationWriter writer =
new ApplicationWriter(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
index 7b1c369..faff5a4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
@@ -9,13 +9,13 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
import com.android.tools.r8.jasmin.JasminTestBase;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import org.junit.Assert;
@@ -127,7 +127,7 @@
"return");
Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
- jasminBuilder.writeJar(riJar, new DefaultDiagnosticsHandler());
+ jasminBuilder.writeJar(riJar, new DiagnosticsHandler() {});
ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
Assert.assertEquals(riResult.toString(), 0, riResult.exitCode);
@@ -174,7 +174,7 @@
"return");
Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
- jasminBuilder.writeJar(riJar, new DefaultDiagnosticsHandler());
+ jasminBuilder.writeJar(riJar, new DiagnosticsHandler() {});
ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
Assert.assertEquals(riResult.toString(), 1, riResult.exitCode);
assertTrue(riResult.stderr.contains("VerifyError"));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
index 44720ed..1eddbd3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
@@ -13,19 +13,18 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.debug.CfDebugTestConfig;
import com.android.tools.r8.debug.DebugTestBase;
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.debug.DexDebugTestConfig;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.code.CheckCast;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Streams;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
@@ -82,7 +81,8 @@
ClassSubject classSubject = inspector.clazz(MAIN);
MethodSubject method = classSubject.method("void", "differentLocals", ImmutableList.of());
assertThat(method, isPresent());
- long count = countCheckCast(method.getMethod().getCode());
+ long count =
+ Streams.stream(method.iterateInstructions(InstructionSubject::isCheckCast)).count();
assertEquals(1, count);
DebugTestConfig config = backend == Backend.CF
@@ -134,7 +134,8 @@
ClassSubject classSubject = inspector.clazz(MAIN);
MethodSubject method = classSubject.method("void", "sameLocal", ImmutableList.of());
assertThat(method, isPresent());
- long count = countCheckCast(method.getMethod().getCode());
+ long count =
+ Streams.stream(method.iterateInstructions(InstructionSubject::isCheckCast)).count();
assertEquals(1, count);
DebugTestConfig config = backend == Backend.CF
@@ -166,13 +167,4 @@
);
}
- private long countCheckCast(Code code) {
- if (backend == Backend.DEX) {
- return filterInstructionKind(code.asDexCode(), CheckCast.class).count();
- } else {
- assert backend == Backend.CF;
- return filterInstructionKind(code.asCfCode(), CfCheckCast.class).count();
- }
- }
-
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
index caa697b..e65ebca 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
@@ -40,6 +40,7 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FieldAccessInstructionSubject;
@@ -429,10 +430,11 @@
}
private String getProguardConfig(String main) {
- return keepMainProguardConfiguration(main)
- + "\n"
- + "-dontobfuscate\n"
- + "-allowaccessmodification";
+ return StringUtils.joinLines(
+ keepMainProguardConfiguration(main),
+ "-dontobfuscate",
+ "-allowaccessmodification",
+ "-keepattributes LineNumberTable");
}
private void configure(InternalOptions options) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 67afdd7..6b7a7c2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -10,7 +10,6 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.code.InvokeStatic;
import com.android.tools.r8.code.NewInstance;
import com.android.tools.r8.code.SgetObject;
import com.android.tools.r8.graph.DexClass;
@@ -19,9 +18,12 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import com.google.common.collect.Streams;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -229,8 +231,8 @@
private List<String> collectStaticCalls(ClassSubject clazz, String methodName, String... params) {
assertNotNull(clazz);
MethodSignature signature = new MethodSignature(methodName, "void", params);
- DexCode code = clazz.method(signature).getMethod().getCode().asDexCode();
- return filterInstructionKind(code, InvokeStatic.class)
+ MethodSubject method = clazz.method(signature);
+ return Streams.stream(method.iterateInstructions(InstructionSubject::isInvokeStatic))
.map(insn -> insn.getMethod().toSourceString())
.sorted()
.collect(Collectors.toList());
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 43bf86e..4f91609 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -59,7 +59,6 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -660,7 +659,7 @@
List<String> classes, int minApi, boolean intermediate, int methodCount)
throws IOException, ExecutionException {
return generateApplication(
- classes, minApi, intermediate, methodCount, new DefaultDiagnosticsHandler());
+ classes, minApi, intermediate, methodCount, new DiagnosticsHandler() {});
}
private static AndroidApp generateApplication(
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java b/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java
new file mode 100644
index 0000000..b280242
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java
@@ -0,0 +1,95 @@
+// 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.memberrebinding;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.R8Command.Builder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class IndirectSuperInterfaceTest extends TestBase {
+
+ public interface Interface {
+ @NeverInline
+ default void foo() {
+ System.out.print("Interface::foo ");
+ }
+ }
+
+ public static class A implements Interface {
+ // Intentionally empty.
+ }
+
+ public static class B extends A {
+ @Override
+ public void foo() {
+ System.out.print("B::foo ");
+ super.foo();
+ }
+
+ public static void main(String[] args) {
+ new B().foo();
+ }
+ }
+
+ private final Backend backend;
+
+ @Parameters(name = "{0}")
+ public static Backend[] setup() {
+ return new Backend[] {Backend.CF, Backend.DEX};
+ }
+
+ public IndirectSuperInterfaceTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void test() throws Exception {
+ String expected = "B::foo Interface::foo ";
+ String reference = runOnJava(B.class);
+ assertEquals(expected, reference);
+
+ AndroidAppConsumers sink = new AndroidAppConsumers();
+ Builder builder =
+ R8Command.builder()
+ .addClassProgramData(ToolHelper.getClassAsBytes(Interface.class), Origin.unknown())
+ .addClassProgramData(ToolHelper.getClassAsBytes(A.class), Origin.unknown())
+ .addClassProgramData(ToolHelper.getClassAsBytes(B.class), Origin.unknown())
+ .setProgramConsumer(sink.wrapProgramConsumer(emptyConsumer(backend)))
+ .addLibraryFiles(runtimeJar(backend))
+ .addProguardConfiguration(
+ ImmutableList.of(
+ "-keep class " + Interface.class.getTypeName(),
+ "-keep class " + A.class.getTypeName(),
+ keepMainProguardConfigurationWithInliningAnnotation(B.class)),
+ Origin.unknown());
+ ToolHelper.allowTestProguardOptions(builder);
+ if (backend == Backend.DEX) {
+ builder.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm().getLevel());
+ }
+ R8.run(builder.build());
+
+ ProcessResult result = runOnVMRaw(sink.build(), B.class, backend);
+
+ // TODO(b/117407667): Assert the test does not fail once fixed.
+ assertTrue(result.toString(), result.exitCode == (backend == Backend.DEX ? 0 : 1));
+ if (result.exitCode == 0) {
+ assertEquals(reference, result.stdout);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index e340c98..719fe80 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.shaking.RootSetBuilder;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.ThreadUtils;
@@ -70,8 +69,7 @@
throws IOException, ProguardRuleParserException, ExecutionException {
ProguardConfiguration configuration =
ToolHelper.loadProguardConfiguration(dexItemFactory, configPaths);
- InternalOptions options = new InternalOptions(configuration,
- new Reporter(new DefaultDiagnosticsHandler()));
+ InternalOptions options = new InternalOptions(configuration, new Reporter());
ExecutorService executor = ThreadUtils.getExecutorService(1);
diff --git a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
index 9ccc94b..5127a59 100644
--- a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
+++ b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
@@ -112,6 +112,7 @@
+ " <methods>;"
+ "}",
"-printmapping",
+ "-keepattributes LineNumberTable",
reflectionRules),
Origin.unknown())
.setOutput(out, outputMode(backend));
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java
new file mode 100644
index 0000000..275d2e9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java
@@ -0,0 +1,122 @@
+// 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.shaking;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.debuginfo.DebugInfoInspector;
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes.TestKeepAttributes;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+
+public class KeepAttributesTest extends TestBase {
+
+ public static final Class CLASS = TestKeepAttributes.class;
+
+ @Test
+ public void discardAllAttributes()
+ throws CompilationFailedException, IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }"
+ );
+ CodeInspector inspector = compile(keepRules);
+ DebugInfoInspector debugInfo = debugInfoForMain(inspector);
+ checkLineNumbers(false, debugInfo);
+ checkLocals(false, debugInfo);
+ }
+
+ @Test
+ public void keepLineNumberTable()
+ throws CompilationFailedException, IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }",
+ "-keepattributes " + ProguardKeepAttributes.LINE_NUMBER_TABLE
+ );
+ CodeInspector inspector = compile(keepRules);
+ DebugInfoInspector debugInfo = debugInfoForMain(inspector);
+ checkLineNumbers(true, debugInfo);
+ checkLocals(false, debugInfo);
+ }
+
+ @Test
+ public void keepLineNumberTableAndLocalVariableTable()
+ throws CompilationFailedException, IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }",
+ "-keepattributes "
+ + ProguardKeepAttributes.LINE_NUMBER_TABLE
+ + ", "
+ + ProguardKeepAttributes.LOCAL_VARIABLE_TABLE
+ );
+ CodeInspector inspector = compile(keepRules);
+ DebugInfoInspector debugInfo = debugInfoForMain(inspector);
+ checkLineNumbers(true, debugInfo);
+ checkLocals(true, debugInfo);
+ }
+
+ @Test
+ public void keepLocalVariableTable() throws IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }",
+ "-keepattributes " + ProguardKeepAttributes.LOCAL_VARIABLE_TABLE
+ );
+ // Compiling with a keep rule for locals but no line results in an error in R8.
+ try {
+ compile(keepRules);
+ } catch (CompilationFailedException e) {
+ assertTrue(e.getCause().getMessage().contains(ProguardKeepAttributes.LOCAL_VARIABLE_TABLE));
+ assertTrue(e.getCause().getMessage().contains(ProguardKeepAttributes.LINE_NUMBER_TABLE));
+ return;
+ }
+ fail("Expected error");
+ }
+
+ private CodeInspector compile(List<String> keepRules)
+ throws CompilationFailedException, IOException, ExecutionException {
+ Path dexOut = temp.getRoot().toPath().resolve("dex.zip");
+ R8.run(R8Command.builder()
+ .setMode(CompilationMode.DEBUG)
+ .addProgramFiles(ToolHelper.getClassFileForTestClass(CLASS))
+ .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
+ .addProguardConfiguration(keepRules, Origin.unknown())
+ .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(dexOut))
+ .build());
+ ToolHelper.runArtRaw(dexOut.toString(), CLASS.getCanonicalName());
+ return new CodeInspector(dexOut);
+ }
+
+ private DebugInfoInspector debugInfoForMain(CodeInspector inspector) {
+ return new DebugInfoInspector(
+ inspector,
+ CLASS.getCanonicalName(),
+ new MethodSignature("main", "void", Collections.singleton("java.lang.String[]")));
+ }
+
+ private void checkLineNumbers(boolean expected, DebugInfoInspector debugInfo) {
+ assertEquals("Expected " + (expected ? "line entries" : "no line entries"),
+ expected, debugInfo.getEntries().stream().anyMatch(e -> e.lineEntry));
+ }
+
+ private void checkLocals(boolean expected, DebugInfoInspector debugInfo) {
+ assertEquals("Expected " + (expected ? "locals" : "no locals"),
+ expected, debugInfo.getEntries().stream().anyMatch(e -> !e.locals.isEmpty()));
+ }
+}
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 f8907d6..1ee19bc 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.position.TextRange;
import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
import com.android.tools.r8.utils.AbortException;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.KeepingDiagnosticHandler;
@@ -208,8 +207,7 @@
public void parseNonJavaIdentifiers() throws Exception {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(dexItemFactory,
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(dexItemFactory, new Reporter());
String nonJavaIdentifiers =
String.join("\n", ImmutableList.of(
"-keep class -package-.-ClassNameWithDash-{",
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 7e4c4ef..9f9b797 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
@@ -33,7 +33,6 @@
import com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes.TestKeepAttributes;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -162,8 +161,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility && hasDefaultConstructor) {
@@ -283,8 +281,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
@@ -383,8 +380,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
@@ -489,8 +485,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
@@ -605,8 +600,7 @@
// Check the Proguard compatibility configuration generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
System.out.println(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
@@ -657,8 +651,7 @@
inspection.accept(new CodeInspector(app));
// Check the Proguard compatibility configuration generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
compatInspection.accept(configuration);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index 3203f9c..dedb839 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -24,6 +24,8 @@
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfThrow;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.code.ValueType;
import org.objectweb.asm.Opcodes;
@@ -40,6 +42,41 @@
}
@Override
+ public boolean isInstancePut() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTFIELD;
+ }
+
+ @Override
+ public boolean isStaticPut() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTSTATIC;
+ }
+
+ @Override
+ public boolean isInstanceGet() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETFIELD;
+ }
+
+ @Override
+ public boolean isStaticGet() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETSTATIC;
+ }
+
+ @Override
+ public DexField getField() {
+ assert isFieldAccess();
+ return ((CfFieldInstruction) instruction).getField();
+ }
+
+ @Override
+ public boolean isInvoke() {
+ return instruction instanceof CfInvoke || instruction instanceof CfInvokeDynamic;
+ }
+
+ @Override
public boolean isInvokeVirtual() {
return instruction instanceof CfInvoke
&& ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKEVIRTUAL;
@@ -58,6 +95,12 @@
}
@Override
+ public DexMethod getMethod() {
+ assert isInvoke();
+ return ((CfInvoke) instruction).getMethod();
+ }
+
+ @Override
public boolean isNop() {
return instruction instanceof CfNop;
}
@@ -105,40 +148,11 @@
}
@Override
- public boolean isInvoke() {
- return instruction instanceof CfInvoke || instruction instanceof CfInvokeDynamic;
- }
-
- @Override
public boolean isNewInstance() {
return instruction instanceof CfNew;
}
@Override
- public boolean isInstancePut() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTFIELD;
- }
-
- @Override
- public boolean isStaticPut() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTSTATIC;
- }
-
- @Override
- public boolean isInstanceGet() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETFIELD;
- }
-
- @Override
- public boolean isStaticGet() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETSTATIC;
- }
-
- @Override
public boolean isCheckCast() {
return instruction instanceof CfCheckCast;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
index 4ea699a..e1d74c1 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
@@ -67,6 +67,8 @@
import com.android.tools.r8.code.SputShort;
import com.android.tools.r8.code.SputWide;
import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
public class DexInstructionSubject implements InstructionSubject {
protected final Instruction instruction;
@@ -81,6 +83,65 @@
}
@Override
+ public boolean isInstanceGet() {
+ return instruction instanceof Iget
+ || instruction instanceof IgetBoolean
+ || instruction instanceof IgetByte
+ || instruction instanceof IgetShort
+ || instruction instanceof IgetChar
+ || instruction instanceof IgetWide
+ || instruction instanceof IgetObject;
+ }
+
+ @Override
+ public boolean isInstancePut() {
+ return instruction instanceof Iput
+ || instruction instanceof IputBoolean
+ || instruction instanceof IputByte
+ || instruction instanceof IputShort
+ || instruction instanceof IputChar
+ || instruction instanceof IputWide
+ || instruction instanceof IputObject;
+ }
+
+ @Override
+ public boolean isStaticGet() {
+ return instruction instanceof Sget
+ || instruction instanceof SgetBoolean
+ || instruction instanceof SgetByte
+ || instruction instanceof SgetShort
+ || instruction instanceof SgetChar
+ || instruction instanceof SgetWide
+ || instruction instanceof SgetObject;
+ }
+
+ @Override
+ public boolean isStaticPut() {
+ return instruction instanceof Sput
+ || instruction instanceof SputBoolean
+ || instruction instanceof SputByte
+ || instruction instanceof SputShort
+ || instruction instanceof SputChar
+ || instruction instanceof SputWide
+ || instruction instanceof SputObject;
+ }
+
+ @Override
+ public DexField getField() {
+ assert isFieldAccess();
+ return instruction.getField();
+ }
+
+ @Override
+ public boolean isInvoke() {
+ return isInvokeVirtual()
+ || isInvokeInterface()
+ || isInvokeDirect()
+ || isInvokeSuper()
+ || isInvokeStatic();
+ }
+
+ @Override
public boolean isInvokeVirtual() {
return instruction instanceof InvokeVirtual || instruction instanceof InvokeVirtualRange;
}
@@ -95,6 +156,20 @@
return instruction instanceof InvokeStatic || instruction instanceof InvokeStaticRange;
}
+ public boolean isInvokeSuper() {
+ return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
+ }
+
+ public boolean isInvokeDirect() {
+ return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
+ }
+
+ @Override
+ public DexMethod getMethod() {
+ assert isInvoke();
+ return instruction.getMethod();
+ }
+
@Override
public boolean isNop() {
return instruction instanceof Nop;
@@ -147,15 +222,6 @@
}
@Override
- public boolean isInvoke() {
- return isInvokeVirtual()
- || isInvokeInterface()
- || isInvokeDirect()
- || isInvokeSuper()
- || isInvokeStatic();
- }
-
- @Override
public boolean isNewInstance() {
return instruction instanceof NewInstance;
}
@@ -170,63 +236,11 @@
return isCheckCast() && ((CheckCast) instruction).getType().toString().equals(type);
}
- public boolean isInvokeSuper() {
- return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
- }
-
- public boolean isInvokeDirect() {
- return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
- }
-
public boolean isConst4() {
return instruction instanceof Const4;
}
@Override
- public boolean isInstanceGet() {
- return instruction instanceof Iget
- || instruction instanceof IgetBoolean
- || instruction instanceof IgetByte
- || instruction instanceof IgetShort
- || instruction instanceof IgetChar
- || instruction instanceof IgetWide
- || instruction instanceof IgetObject;
- }
-
- @Override
- public boolean isInstancePut() {
- return instruction instanceof Iput
- || instruction instanceof IputBoolean
- || instruction instanceof IputByte
- || instruction instanceof IputShort
- || instruction instanceof IputChar
- || instruction instanceof IputWide
- || instruction instanceof IputObject;
- }
-
- @Override
- public boolean isStaticGet() {
- return instruction instanceof Sget
- || instruction instanceof SgetBoolean
- || instruction instanceof SgetByte
- || instruction instanceof SgetShort
- || instruction instanceof SgetChar
- || instruction instanceof SgetWide
- || instruction instanceof SgetObject;
- }
-
- @Override
- public boolean isStaticPut() {
- return instruction instanceof Sput
- || instruction instanceof SputBoolean
- || instruction instanceof SputByte
- || instruction instanceof SputShort
- || instruction instanceof SputChar
- || instruction instanceof SputWide
- || instruction instanceof SputObject;
- }
-
- @Override
public boolean isIf() {
return instruction instanceof IfEq
|| instruction instanceof IfEqz
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index e7eaa60..fb0e0d3 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.utils.codeinspector;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+
public interface InstructionSubject {
enum JumboStringMode {
@@ -13,12 +16,26 @@
boolean isFieldAccess();
+ boolean isInstancePut();
+
+ boolean isStaticPut();
+
+ boolean isInstanceGet();
+
+ boolean isStaticGet();
+
+ DexField getField();
+
+ boolean isInvoke();
+
boolean isInvokeVirtual();
boolean isInvokeInterface();
boolean isInvokeStatic();
+ DexMethod getMethod();
+
boolean isNop();
boolean isConstString(JumboStringMode jumboStringMode);
@@ -37,18 +54,8 @@
boolean isThrow();
- boolean isInvoke();
-
boolean isNewInstance();
- boolean isInstancePut();
-
- boolean isStaticPut();
-
- boolean isInstanceGet();
-
- boolean isStaticGet();
-
boolean isCheckCast();
boolean isCheckCast(String type);