Merge commit '2d3c611f14193325be90abc1921bd68c075efc4e' into dev-release
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 2b6eb5f..ee1883c 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -149,6 +149,33 @@
}
}
builders {
+ name: "linux-jdk8"
+ mixins: "linux"
+ mixins: "normal"
+ priority: 26
+ recipe {
+ properties_j: "test_options:[\"--runtimes=jdk8\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
+ }
+ }
+ builders {
+ name: "linux-jdk9"
+ mixins: "linux"
+ mixins: "normal"
+ priority: 26
+ recipe {
+ properties_j: "test_options:[\"--runtimes=jdk9\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
+ }
+ }
+ builders {
+ name: "linux-jdk8_9"
+ mixins: "linux"
+ mixins: "normal"
+ priority: 26
+ recipe {
+ properties_j: "test_options:[\"--runtimes=jdk8:jdk9\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
+ }
+ }
+ builders {
name: "linux_horizontal"
mixins: "linux"
mixins: "normal"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 90e3efc..bec8477 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -16,6 +16,21 @@
short_name: "linux"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk8"
+ category: "R8"
+ short_name: "jdk8"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk9"
+ category: "R8"
+ short_name: "jdk9"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk8_9"
+ category: "R8"
+ short_name: "jdk8_9"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/linux_horizontal"
category: "R8"
short_name: "horizontal"
diff --git a/infra/config/global/luci-notify.cfg b/infra/config/global/luci-notify.cfg
index e417700..4ed7592 100644
--- a/infra/config/global/luci-notify.cfg
+++ b/infra/config/global/luci-notify.cfg
@@ -29,6 +29,21 @@
repository: "https://r8.googlesource.com/r8"
}
builders {
+ name: "linux-jdk8"
+ bucket: "ci"
+ repository: "https://r8.googlesource.com/r8"
+ }
+ builders {
+ name: "linux-jdk9"
+ bucket: "ci"
+ repository: "https://r8.googlesource.com/r8"
+ }
+ builders {
+ name: "linux-jdk8_9"
+ bucket: "ci"
+ repository: "https://r8.googlesource.com/r8"
+ }
+ builders {
name: "linux_horizontal"
bucket: "ci"
repository: "https://r8.googlesource.com/r8"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index fcf4105..634885f 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -27,6 +27,9 @@
}
triggers: "archive"
triggers: "linux"
+ triggers: "linux-jdk8"
+ triggers: "linux-jdk9"
+ triggers: "linux-jdk8_9"
triggers: "linux_horizontal"
triggers: "linux-android-4.0.4"
triggers: "linux-android-4.4.4"
@@ -138,6 +141,49 @@
}
job {
+ id: "linux-jdk8"
+ acl_sets: "default"
+ triggering_policy: {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 2
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-jdk8"
+ }
+}
+
+job {
+ id: "linux-jdk9"
+ acl_sets: "default"
+ triggering_policy: {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 2
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-jdk9"
+ }
+}
+
+job {
+ id: "linux-jdk8_9"
+ acl_sets: "default"
+ triggering_policy: {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 2
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-jdk8_9"
+ }
+}
+
+
+job {
id: "linux_horizontal"
acl_sets: "default"
triggering_policy: {
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
index 18b86c7..45878c9 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
@@ -19,6 +19,7 @@
protected static final String MIN_API_FLAG = "--min-api";
protected static final String THREAD_COUNT_FLAG = "--thread-count";
+ protected static final String MAP_DIAGNOSTICS = "--map-diagnostics";
static final Iterable<String> ASSERTIONS_USAGE_MESSAGE =
Arrays.asList(
@@ -43,6 +44,17 @@
" # the number will be based on heuristics taking the number",
" # of cores into account.");
+ static final Iterable<String> MAP_DIAGNOSTICS_USAGE_MESSAGE =
+ Arrays.asList(
+ " " + MAP_DIAGNOSTICS + "[:<type>] <from-level> <to-level>",
+ " # Map diagnostics of <type> (default any) reported as",
+ " # <from-level> to <to-level> where <from-level> and",
+ " # <to-level> are one of 'info', 'warning', or 'error' and the",
+ " # optional <type> is either the simple or fully qualified",
+ " # Java type name of a diagnostic. If <type> is unspecified,",
+ " # all diagnostics at <from-level> will be mapped.",
+ " # Note that fatal compiler errors cannot be mapped.");
+
public static void parsePositiveIntArgument(
Consumer<Diagnostic> errorConsumer,
String flag,
@@ -140,6 +152,52 @@
}
}
+ private DiagnosticsLevel tryParseLevel(B builder, String arg, Origin origin) {
+ if (arg.equals("error")) {
+ return DiagnosticsLevel.ERROR;
+ }
+ if (arg.equals("warning")) {
+ return DiagnosticsLevel.WARNING;
+ }
+ if (arg.equals("info")) {
+ return DiagnosticsLevel.INFO;
+ }
+ builder.error(
+ new StringDiagnostic(
+ "Invalid diagnostics level '"
+ + arg
+ + "'. Valid levels are 'error', 'warning' and 'info'.",
+ origin));
+
+ return null;
+ }
+
+ int tryParseMapDiagnostics(B builder, String arg, String[] args, int argsIndex, Origin origin) {
+ if (!arg.startsWith(MAP_DIAGNOSTICS)) {
+ return -1;
+ }
+ if (args.length <= argsIndex + 2) {
+ builder.error(new StringDiagnostic("Missing argument(s) for " + arg + ".", origin));
+ return args.length - argsIndex;
+ }
+ String remaining = arg.substring(MAP_DIAGNOSTICS.length());
+ String diagnosticsClassName = "";
+ if (remaining.length() > 0) {
+ if (remaining.length() == 1 || remaining.charAt(0) != ':') {
+ builder.error(
+ new StringDiagnostic("Invalid diagnostics type specification " + arg + ".", origin));
+ return 0;
+ }
+ diagnosticsClassName = remaining.substring(1);
+ }
+ DiagnosticsLevel from = tryParseLevel(builder, args[argsIndex + 1], origin);
+ DiagnosticsLevel to = tryParseLevel(builder, args[argsIndex + 2], origin);
+ if (from != null && to != null) {
+ builder.getReporter().addDiagnosticsLevelMapping(from, diagnosticsClassName, to);
+ }
+ return 2;
+ }
+
/**
* This method must match the lookup in
* {@link com.android.tools.r8.JdkClassFileProvider#fromJdkHome}.
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 0a38fb5..8e56a8e 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -249,7 +249,10 @@
Marker marker = options.getMarker(Tool.D8);
Set<Marker> markers = new HashSet<>(appView.dexItemFactory().extractMarkers());
// TODO(b/166617364): Don't add an additional marker when desugaring is turned off.
- if (hasClassResources && (options.desugarState != DesugarState.OFF || markers.isEmpty())) {
+ if (hasClassResources
+ && (options.desugarState != DesugarState.OFF
+ || markers.isEmpty()
+ || (markers.size() == 1 && markers.iterator().next().isL8()))) {
markers.add(marker);
}
Marker.checkCompatibleDesugaredLibrary(markers, options.reporter);
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index 2ed9890..d705c8e 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -144,6 +144,7 @@
" # Output resulting main dex list in <file>."),
ASSERTIONS_USAGE_MESSAGE,
THREAD_COUNT_USAGE_MESSAGE,
+ MAP_DIAGNOSTICS_USAGE_MESSAGE,
Arrays.asList(
" --version # Print the version of d8.",
" --help # Print this message.")));
@@ -276,10 +277,15 @@
} else if (arg.equals("--desugared-lib")) {
builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg)));
} else if (arg.startsWith("--")) {
- if (!tryParseAssertionArgument(builder, arg, origin)) {
- builder.error(new StringDiagnostic("Unknown option: " + arg, origin));
+ if (tryParseAssertionArgument(builder, arg, origin)) {
continue;
}
+ int argsConsumed = tryParseMapDiagnostics(builder, arg, expandedArgs, i, origin);
+ if (argsConsumed >= 0) {
+ i += argsConsumed;
+ continue;
+ }
+ builder.error(new StringDiagnostic("Unknown option: " + arg, origin));
} else if (arg.startsWith("@")) {
builder.error(new StringDiagnostic("Recursive @argfiles are not supported: ", origin));
} else {
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index f3acbec..b77db45 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -356,7 +356,7 @@
private void run() throws Exception {
// Run over all the API levels that the desugared library can be compiled with.
- for (int apiLevel = AndroidApiLevel.Q.getLevel();
+ for (int apiLevel = AndroidApiLevel.LATEST.getLevel();
apiLevel >= desugaredLibraryConfiguration.getRequiredCompilationApiLevel().getLevel();
apiLevel--) {
System.out.println("Generating lint files for compile API " + apiLevel);
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 221df4c..1141688 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -316,6 +316,7 @@
r8Builder.addProguardConfiguration(
libraryConfiguration.getExtraKeepRules(), Origin.unknown());
r8Builder.addProguardConfigurationFiles(proguardConfigFiles);
+ r8Builder.setDisableDesugaring(true);
r8Command = r8Builder.makeCommand();
} else if (!(getProgramConsumer() instanceof ClassFileConsumer)) {
l8CfConsumer = new InMemoryJarContent();
@@ -333,6 +334,7 @@
inputs.getLibraryResourceProviders()) {
d8Builder.addLibraryResourceProvider(libraryResourceProvider);
}
+ d8Builder.setDisableDesugaring(true);
d8Command = d8Builder.makeCommand();
} else {
assert getProgramConsumer() instanceof ClassFileConsumer;
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java
index e816320..0a57389 100644
--- a/src/main/java/com/android/tools/r8/L8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -55,6 +55,7 @@
+ " (json)."),
ASSERTIONS_USAGE_MESSAGE,
THREAD_COUNT_USAGE_MESSAGE,
+ MAP_DIAGNOSTICS_USAGE_MESSAGE,
Arrays.asList(
" --version # Print the version of l8.",
" --help # Print this message.")));
@@ -156,10 +157,15 @@
parsePositiveIntArgument(
builder::error, THREAD_COUNT_FLAG, nextArg, origin, builder::setThreadCount);
} else if (arg.startsWith("--")) {
- if (!tryParseAssertionArgument(builder, arg, origin)) {
- builder.error(new StringDiagnostic("Unknown option: " + arg, origin));
+ if (tryParseAssertionArgument(builder, arg, origin)) {
continue;
}
+ int argsConsumed = tryParseMapDiagnostics(builder, arg, expandedArgs, i, origin);
+ if (argsConsumed >= 0) {
+ i += argsConsumed;
+ continue;
+ }
+ builder.error(new StringDiagnostic("Unknown option: " + arg, origin));
} else {
builder.addProgramFiles(Paths.get(arg));
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5e8e3a6..dad6c63 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -313,6 +313,7 @@
}
if (!options.desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
DesugaredLibraryRetargeter.checkForAssumedLibraryTypes(appView);
+ DesugaredLibraryRetargeter.amendLibraryWithRetargetedMembers(appView);
}
InterfaceMethodRewriter.checkForAssumedLibraryTypes(appView.appInfo(), options);
BackportedMethodRewriter.registerAssumedLibraryTypes(options);
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java
index b796705..3cb01e1 100644
--- a/src/main/java/com/android/tools/r8/R8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -100,6 +100,7 @@
" # Output the full main-dex list in <file>."),
ASSERTIONS_USAGE_MESSAGE,
THREAD_COUNT_USAGE_MESSAGE,
+ MAP_DIAGNOSTICS_USAGE_MESSAGE,
Arrays.asList(
" --version # Print the version of r8.",
" --help # Print this message.")));
@@ -262,10 +263,15 @@
} else if (arg.equals("--no-data-resources")) {
state.includeDataResources = false;
} else if (arg.startsWith("--")) {
- if (!tryParseAssertionArgument(builder, arg, argsOrigin)) {
- builder.error(new StringDiagnostic("Unknown option: " + arg, argsOrigin));
+ if (tryParseAssertionArgument(builder, arg, argsOrigin)) {
continue;
}
+ int argsConsumed = tryParseMapDiagnostics(builder, arg, expandedArgs, i, argsOrigin);
+ if (argsConsumed >= 0) {
+ i += argsConsumed;
+ continue;
+ }
+ builder.error(new StringDiagnostic("Unknown option: " + arg, argsOrigin));
} else if (arg.startsWith("@")) {
builder.error(new StringDiagnostic("Recursive @argfiles are not supported: ", argsOrigin));
} else {
diff --git a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
index e3584ec..b43a42c 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
@@ -115,7 +115,7 @@
// When not coming from DEX input we require interfaces to be abstract - except for
// package-info classes - as both old versions of javac and other tools can produce
// package-info classes that are interfaces but not abstract.
- if (version.isGreaterThanOrEqual(Constants.CORRESPONDING_CLASS_FILE_VERSION)
+ if (version.isGreaterThan(Constants.CORRESPONDING_CLASS_FILE_VERSION)
&& !isAbstract()
&& !isPackageInfo) {
return false;
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index 9757af4..a0d4cbe 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -250,6 +250,11 @@
return factory.isConstructor(this);
}
+ public DexMethod withExtraArgumentPrepended(DexType type, DexItemFactory dexItemFactory) {
+ return dexItemFactory.createMethod(
+ holder, dexItemFactory.prependTypeToProto(type, proto), name);
+ }
+
public DexMethod withHolder(DexType holder, DexItemFactory dexItemFactory) {
return dexItemFactory.createMethod(holder, proto, name);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 3295733..54d6795 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -218,6 +218,12 @@
return self();
}
+ public Builder addLibraryClasses(Collection<DexLibraryClass> classes) {
+ libraryClasses =
+ ImmutableList.<DexLibraryClass>builder().addAll(libraryClasses).addAll(classes).build();
+ return self();
+ }
+
@Override
public DirectMappedDexApplication build() {
// Rebuild the map. This will fail if keys are not unique.
diff --git a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
index 5457311..82f34d7 100644
--- a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
@@ -32,6 +32,10 @@
this.enclosingMethod = enclosingMethod;
}
+ public static EnclosingMethodAttribute none() {
+ return null;
+ }
+
public void write(ClassWriter writer, NamingLens lens) {
if (enclosingMethod != null) {
writer.visitOuterClass(
diff --git a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
index f3195c9..d54bc7b 100644
--- a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import java.util.Collections;
+import java.util.List;
import java.util.function.Consumer;
import org.objectweb.asm.ClassWriter;
@@ -39,6 +41,10 @@
this.innerName = innerName;
}
+ public static List<InnerClassAttribute> emptyList() {
+ return Collections.emptyList();
+ }
+
public void forEachType(Consumer<DexType> consumer) {
if (inner != null) {
consumer.accept(inner);
diff --git a/src/main/java/com/android/tools/r8/graph/NestHostClassAttribute.java b/src/main/java/com/android/tools/r8/graph/NestHostClassAttribute.java
index 96fb82b..e007f4e 100644
--- a/src/main/java/com/android/tools/r8/graph/NestHostClassAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/NestHostClassAttribute.java
@@ -19,6 +19,10 @@
return nestHost;
}
+ public static NestHostClassAttribute none() {
+ return null;
+ }
+
public void write(ClassWriter writer, NamingLens lens) {
assert nestHost != null;
writer.visitNestHost(lens.lookupInternalName(nestHost));
diff --git a/src/main/java/com/android/tools/r8/graph/NestMemberClassAttribute.java b/src/main/java/com/android/tools/r8/graph/NestMemberClassAttribute.java
index f88a39f..f9d1a35 100644
--- a/src/main/java/com/android/tools/r8/graph/NestMemberClassAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/NestMemberClassAttribute.java
@@ -5,6 +5,8 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.naming.NamingLens;
+import java.util.Collections;
+import java.util.List;
import org.objectweb.asm.ClassWriter;
public class NestMemberClassAttribute {
@@ -15,6 +17,10 @@
this.nestMember = nestMember;
}
+ public static List<NestMemberClassAttribute> emptyList() {
+ return Collections.emptyList();
+ }
+
public DexType getNestMember() {
return nestMember;
}
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 c271af1..960dea0 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
@@ -48,7 +48,6 @@
import com.android.tools.r8.ir.desugar.D8NestBasedAccessDesugaring;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.Mode;
-import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor;
@@ -214,13 +213,18 @@
.map(options.itemFactory::createString)
.collect(Collectors.toList());
if (options.isDesugaredLibraryCompilation()) {
- // Specific L8 Settings.
- // DesugaredLibraryRetargeter is needed for retarget core library members and backports.
- // InterfaceMethodRewriter is needed for emulated interfaces.
- // LambdaRewriter is needed because if it is missing there are invoke custom on
- // default/static interface methods, and this is not supported by the compiler.
- // DesugaredLibraryAPIConverter is here to duplicate APIs.
- // The rest is nulled out. In addition the rewriting logic fails without lambda rewriting.
+ // Specific L8 Settings, performs all desugaring including L8 specific desugaring.
+ // The following desugaring are required for L8 specific desugaring:
+ // - DesugaredLibraryRetargeter for retarget core library members.
+ // - InterfaceMethodRewriter for emulated interfaces,
+ // - LambdaRewriter since InterfaceMethodDesugaring does not support invokeCustom rewriting,
+ // - DesugaredLibraryAPIConverter to duplicate APIs.
+ // The following desugaring are present so all desugaring is performed cf to cf in L8, and
+ // the second L8 phase can just run with Desugar turned off:
+ // - InterfaceMethodRewriter for non L8 specific interface method desugaring,
+ // - TwrCloseResourceRewriter,
+ // - NestBaseAccessDesugaring.
+ assert options.desugarState == DesugarState.ON;
this.desugaredLibraryRetargeter =
options.desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
? null
@@ -232,11 +236,11 @@
this.lambdaRewriter = new LambdaRewriter(appView);
this.desugaredLibraryAPIConverter =
new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS);
- this.backportedMethodRewriter =
- options.cfToCfDesugar || options.testing.forceLibBackportsInL8CfToCf
- ? new BackportedMethodRewriter(appView)
- : null;
- this.twrCloseResourceRewriter = null;
+ this.backportedMethodRewriter = new BackportedMethodRewriter(appView);
+ this.twrCloseResourceRewriter =
+ enableTwrCloseResourceDesugaring() ? new TwrCloseResourceRewriter(appView, this) : null;
+ this.d8NestBasedAccessDesugaring =
+ options.shouldDesugarNests() ? new D8NestBasedAccessDesugaring(appView) : null;
this.lambdaMerger = null;
this.covariantReturnTypeAnnotationTransformer = null;
this.dynamicTypeOptimization = null;
@@ -251,7 +255,6 @@
this.identifierNameStringMarker = null;
this.devirtualizer = null;
this.typeChecker = null;
- this.d8NestBasedAccessDesugaring = null;
this.stringSwitchRemover = null;
this.serviceLoaderRewriter = null;
this.methodOptimizationInfoCollector = null;
@@ -552,13 +555,6 @@
return true;
}
if (options.isDesugaredLibraryCompilation()) {
- // TODO(b/169035524): Create method for evaluating if a code object needs rewriting for
- // library desugaring.
- return true;
- }
- if (options.desugaredLibraryConfiguration != DesugaredLibraryConfiguration.empty()) {
- // TODO(b/169035524): Create method for evaluating if a code object needs rewriting for
- // library desugaring.
return true;
}
@@ -569,14 +565,21 @@
return true;
}
- NeedsIRDesugarUseRegistry useRegistry =
- new NeedsIRDesugarUseRegistry(appView, backportedMethodRewriter);
- method.registerCodeReferences(useRegistry);
-
- if (useRegistry.needsDesugaring()) {
+ if (desugaredLibraryAPIConverter != null
+ && desugaredLibraryAPIConverter.shouldRegisterCallback(method)) {
return true;
}
- return false;
+
+ NeedsIRDesugarUseRegistry useRegistry =
+ new NeedsIRDesugarUseRegistry(
+ appView,
+ backportedMethodRewriter,
+ desugaredLibraryRetargeter,
+ interfaceMethodRewriter,
+ desugaredLibraryAPIConverter);
+ method.registerCodeReferences(useRegistry);
+
+ return useRegistry.needsDesugaring();
}
private void checkPrefixMerging(ProgramMethod method) {
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 0512e69..8e1ee32 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
@@ -89,6 +89,7 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.optimize.MemberRebindingAnalysis;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashSet;
@@ -594,7 +595,7 @@
if (definition != null) {
DexClassAndField field = DexClassAndField.create(holder, definition);
if (AccessControl.isMemberAccessible(field, holder, context, appView).isTrue()) {
- return lookup.getReboundReference();
+ return MemberRebindingAnalysis.validMemberRebindingTargetFor(appView, field, reference);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
index 9d88a1f..f6ad5f3 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
@@ -11,6 +11,9 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
+import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
class NeedsIRDesugarUseRegistry extends UseRegistry {
@@ -18,12 +21,22 @@
private boolean needsDesugarging = false;
private final AppView appView;
private final BackportedMethodRewriter backportedMethodRewriter;
+ private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
+ private final InterfaceMethodRewriter interfaceMethodRewriter;
+ private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
public NeedsIRDesugarUseRegistry(
- AppView appView, BackportedMethodRewriter backportedMethodRewriter) {
+ AppView appView,
+ BackportedMethodRewriter backportedMethodRewriter,
+ DesugaredLibraryRetargeter desugaredLibraryRetargeter,
+ InterfaceMethodRewriter interfaceMethodRewriter,
+ DesugaredLibraryAPIConverter desugaredLibraryAPIConverter) {
super(appView.dexItemFactory());
this.appView = appView;
this.backportedMethodRewriter = backportedMethodRewriter;
+ this.desugaredLibraryRetargeter = desugaredLibraryRetargeter;
+ this.interfaceMethodRewriter = interfaceMethodRewriter;
+ this.desugaredLibraryAPIConverter = desugaredLibraryAPIConverter;
}
public boolean needsDesugaring() {
@@ -31,31 +44,75 @@
}
@Override
- public void registerInitClass(DexType type) {}
+ public void registerInitClass(DexType type) {
+ if (!needsDesugarging
+ && desugaredLibraryAPIConverter != null
+ && desugaredLibraryAPIConverter.canConvert(type)) {
+ needsDesugarging = true;
+ }
+ }
@Override
public void registerInvokeVirtual(DexMethod method) {
- if (backportedMethodRewriter.needsDesugaring(method)) {
- needsDesugarging = true;
- }
+ registerBackportedMethodRewriting(method);
+ registerLibraryRetargeting(method, false);
+ registerInterfaceMethodRewriting(method);
+ registerDesugaredLibraryAPIConverter(method);
}
@Override
- public void registerInvokeDirect(DexMethod method) {}
+ public void registerInvokeDirect(DexMethod method) {
+ registerLibraryRetargeting(method, false);
+ registerInterfaceMethodRewriting(method);
+ registerDesugaredLibraryAPIConverter(method);
+ }
+
+ private void registerBackportedMethodRewriting(DexMethod method) {
+ if (!needsDesugarging) {
+ needsDesugarging = backportedMethodRewriter.needsDesugaring(method);
+ }
+ }
+
+ private void registerInterfaceMethodRewriting(DexMethod method) {
+ if (!needsDesugarging) {
+ needsDesugarging =
+ interfaceMethodRewriter != null && interfaceMethodRewriter.needsRewriting(method);
+ }
+ }
+
+ private void registerDesugaredLibraryAPIConverter(DexMethod method) {
+ if (!needsDesugarging) {
+ needsDesugarging =
+ desugaredLibraryAPIConverter != null
+ && desugaredLibraryAPIConverter.shouldRewriteInvoke(method);
+ }
+ }
+
+ private void registerLibraryRetargeting(DexMethod method, boolean b) {
+ if (!needsDesugarging) {
+ needsDesugarging =
+ desugaredLibraryRetargeter != null
+ && desugaredLibraryRetargeter.getRetargetedMethod(method, b) != null;
+ }
+ }
@Override
public void registerInvokeStatic(DexMethod method) {
- if (TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(method, appView)) {
- needsDesugarging = true;
+ if (!needsDesugarging) {
+ needsDesugarging = TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(method, appView);
}
-
- if (backportedMethodRewriter.needsDesugaring(method)) {
- needsDesugarging = true;
- }
+ registerBackportedMethodRewriting(method);
+ registerLibraryRetargeting(method, false);
+ registerInterfaceMethodRewriting(method);
+ registerDesugaredLibraryAPIConverter(method);
}
@Override
- public void registerInvokeInterface(DexMethod method) {}
+ public void registerInvokeInterface(DexMethod method) {
+ registerLibraryRetargeting(method, true);
+ registerInterfaceMethodRewriting(method);
+ registerDesugaredLibraryAPIConverter(method);
+ }
@Override
public void registerInvokeStatic(DexMethod method, boolean itf) {
@@ -72,7 +129,11 @@
}
@Override
- public void registerInvokeSuper(DexMethod method) {}
+ public void registerInvokeSuper(DexMethod method) {
+ registerLibraryRetargeting(method, false);
+ registerInterfaceMethodRewriting(method);
+ registerDesugaredLibraryAPIConverter(method);
+ }
@Override
public void registerInstanceFieldRead(DexField field) {}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 04fb914..11e6e33 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -75,7 +75,7 @@
}
public boolean needsDesugaring(DexMethod method) {
- return rewritableMethods.getProvider(method) != null;
+ return getMethodProviderOrNull(method) != null;
}
public static List<DexMethod> generateListOfBackportedMethods(
@@ -165,7 +165,30 @@
private MethodProvider getMethodProviderOrNull(DexMethod method) {
DexMethod original = appView.graphLens().getOriginalMethodSignature(method);
assert original != null;
- return rewritableMethods.getProvider(original);
+ MethodProvider provider = rewritableMethods.getProvider(original);
+ // TODO(b/150693139): Since the DesugarLibraryRetargeter is run during IR processing while the
+ // backported method rewriter is run in cf to cf, we need here to compute if the method is
+ // actually going to be retargeted through desugared library backports, and compute the
+ // corresponding backported method if so. This can be removed once the DesugarLibraryRetargeter
+ // has been moved as a cf to cf transformation.
+ if (provider == null
+ && appView.options().isDesugaredLibraryCompilation()
+ && appView
+ .options()
+ .desugaredLibraryConfiguration
+ .getBackportCoreLibraryMember()
+ .containsKey(method.holder)) {
+ DexType newHolder =
+ appView
+ .options()
+ .desugaredLibraryConfiguration
+ .getBackportCoreLibraryMember()
+ .get(method.holder);
+ DexMethod backportedMethod =
+ appView.dexItemFactory().createMethod(newHolder, method.proto, method.name);
+ provider = rewritableMethods.getProvider(backportedMethod);
+ }
+ return provider;
}
private static final class RewritableMethods {
@@ -175,15 +198,6 @@
RewritableMethods(InternalOptions options, AppView<?> appView) {
- if (options.testing.forceLibBackportsInL8CfToCf) {
- DexItemFactory factory = options.itemFactory;
- initializeJava9OptionalMethodProviders(factory);
- initializeJava10OptionalMethodProviders(factory);
- initializeJava11OptionalMethodProviders(factory);
- initializeStreamMethodProviders(factory);
- return;
- }
-
if (!options.shouldBackportMethods()) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index bd468b0..787915f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -146,6 +146,9 @@
public void desugarNestBasedAccess(
DexApplication.Builder<?> builder, ExecutorService executorService, IRConverter converter)
throws ExecutionException {
+ if (metNestHosts.isEmpty()) {
+ return;
+ }
processNestsConcurrently(executorService);
addDeferredBridges();
synthesizeNestConstructor(builder);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
index 401297e..c337afe 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
@@ -146,7 +146,7 @@
return true;
}
- private boolean shouldRewriteInvoke(DexMethod invokedMethod) {
+ public boolean shouldRewriteInvoke(DexMethod invokedMethod) {
if (appView.rewritePrefix.hasRewrittenType(invokedMethod.holder, appView)
|| invokedMethod.holder.isArrayType()) {
return false;
@@ -164,7 +164,7 @@
}
}
- private boolean shouldRegisterCallback(ProgramMethod method) {
+ public boolean shouldRegisterCallback(ProgramMethod method) {
// Any override of a library method can be called by the library.
// We duplicate the method to have a vivified type version callable by the library and
// a type version callable by the program. We need to add the vivified version to the rootset
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
index 68a2df3..904ca7e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -4,7 +4,9 @@
package com.android.tools.r8.ir.desugar;
+import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
@@ -22,10 +24,15 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.NestHostClassAttribute;
+import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.ir.code.IRCode;
@@ -42,9 +49,12 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
+import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
@@ -84,6 +94,109 @@
}
}
+ public static void amendLibraryWithRetargetedMembers(AppView<AppInfoWithClassHierarchy> appView) {
+ Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
+ appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
+ Map<DexType, DexLibraryClass> synthesizedLibraryClasses =
+ synthesizeLibraryClassesForRetargetedMembers(appView, retargetCoreLibMember);
+ Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedLibraryMethods =
+ synthesizedMembersForRetargetClasses(
+ appView, retargetCoreLibMember, synthesizedLibraryClasses);
+ synthesizedLibraryMethods.forEach(DexLibraryClass::addDirectMethods);
+ DirectMappedDexApplication newApplication =
+ appView
+ .appInfo()
+ .app()
+ .asDirect()
+ .builder()
+ .addLibraryClasses(synthesizedLibraryClasses.values())
+ .build();
+ appView.setAppInfo(appView.appInfo().rebuildWithClassHierarchy(app -> newApplication));
+ }
+
+ private static Map<DexType, DexLibraryClass> synthesizeLibraryClassesForRetargetedMembers(
+ AppView<AppInfoWithClassHierarchy> appView,
+ Map<DexString, Map<DexType, DexType>> retargetCoreLibMember) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ Map<DexType, DexLibraryClass> synthesizedLibraryClasses = new LinkedHashMap<>();
+ for (Map<DexType, DexType> oldToNewTypeMap : retargetCoreLibMember.values()) {
+ for (DexType newType : oldToNewTypeMap.values()) {
+ if (appView.definitionFor(newType) == null) {
+ synthesizedLibraryClasses.computeIfAbsent(
+ newType,
+ type ->
+ // Synthesize a library class with the given name. Note that this is assuming that
+ // the library class inherits directly from java.lang.Object, does not implement
+ // any interfaces, etc.
+ new DexLibraryClass(
+ type,
+ Kind.CF,
+ new SynthesizedOrigin(
+ "Desugared library retargeter", DesugaredLibraryRetargeter.class),
+ ClassAccessFlags.fromCfAccessFlags(Constants.ACC_PUBLIC),
+ dexItemFactory.objectType,
+ DexTypeList.empty(),
+ dexItemFactory.createString("DesugaredLibraryRetargeter"),
+ NestHostClassAttribute.none(),
+ NestMemberClassAttribute.emptyList(),
+ EnclosingMethodAttribute.none(),
+ InnerClassAttribute.emptyList(),
+ ClassSignature.noSignature(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ dexItemFactory.getSkipNameValidationForTesting()));
+ }
+ }
+ }
+ return synthesizedLibraryClasses;
+ }
+
+ private static Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedMembersForRetargetClasses(
+ AppView<AppInfoWithClassHierarchy> appView,
+ Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
+ Map<DexType, DexLibraryClass> synthesizedLibraryClasses) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedMembers = new IdentityHashMap<>();
+ for (Entry<DexString, Map<DexType, DexType>> entry : retargetCoreLibMember.entrySet()) {
+ DexString methodName = entry.getKey();
+ Map<DexType, DexType> types = entry.getValue();
+ types.forEach(
+ (oldType, newType) -> {
+ DexClass oldClass = appView.definitionFor(oldType);
+ DexLibraryClass newClass = synthesizedLibraryClasses.get(newType);
+ if (oldClass == null || newClass == null) {
+ return;
+ }
+ for (DexEncodedMethod method :
+ oldClass.methods(method -> method.getName() == methodName)) {
+ DexMethod retargetMethod = method.getReference().withHolder(newType, dexItemFactory);
+ if (!method.isStatic()) {
+ retargetMethod = retargetMethod.withExtraArgumentPrepended(oldType, dexItemFactory);
+ }
+ synthesizedMembers
+ .computeIfAbsent(
+ newClass,
+ ignore ->
+ new TreeSet<>((x, y) -> x.getReference().slowCompareTo(y.getReference())))
+ .add(
+ new DexEncodedMethod(
+ retargetMethod,
+ MethodAccessFlags.fromCfAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC, false),
+ MethodTypeSignature.noSignature(),
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ null,
+ true));
+ }
+ });
+ }
+ return synthesizedMembers;
+ }
+
private static void warnMissingRetargetCoreLibraryMember(DexType type, AppView<?> appView) {
StringDiagnostic warning =
new StringDiagnostic(
@@ -155,25 +268,12 @@
}
InvokeMethod invoke = instruction.asInvokeMethod();
- DexMethod retarget = getRetargetLibraryMember(invoke.getInvokedMethod());
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+ boolean isInterface = invoke.getInterfaceBit();
+
+ DexMethod retarget = getRetargetedMethod(invokedMethod, isInterface);
if (retarget == null) {
- if (!matchesNonFinalHolderRewrite(invoke.getInvokedMethod())) {
- continue;
- }
- // We need to force resolution, even on d8, to know if the invoke has to be rewritten.
- ResolutionResult resolutionResult =
- appView
- .appInfoForDesugaring()
- .resolveMethod(invoke.getInvokedMethod(), invoke.getInterfaceBit());
- if (resolutionResult.isFailedResolution()) {
- continue;
- }
- DexEncodedMethod singleTarget = resolutionResult.getSingleTarget();
- assert singleTarget != null;
- retarget = getRetargetLibraryMember(singleTarget.method);
- if (retarget == null) {
- continue;
- }
+ continue;
}
// Due to emulated dispatch, we have to rewrite invoke-super differently or we end up in
@@ -203,6 +303,28 @@
}
}
+ public DexMethod getRetargetedMethod(DexMethod invokedMethod, boolean isInterface) {
+ DexMethod retarget = getRetargetLibraryMember(invokedMethod);
+ if (retarget == null) {
+ if (!matchesNonFinalHolderRewrite(invokedMethod)) {
+ return null;
+ }
+ // We need to force resolution, even on d8, to know if the invoke has to be rewritten.
+ ResolutionResult resolutionResult =
+ appView.appInfoForDesugaring().resolveMethod(invokedMethod, isInterface);
+ if (resolutionResult.isFailedResolution()) {
+ return null;
+ }
+ DexEncodedMethod singleTarget = resolutionResult.getSingleTarget();
+ assert singleTarget != null;
+ retarget = getRetargetLibraryMember(singleTarget.method);
+ if (retarget == null) {
+ return null;
+ }
+ }
+ return retarget;
+ }
+
private DexMethod getRetargetLibraryMember(DexMethod method) {
Map<DexType, DexType> backportCoreLibraryMembers =
appView.options().desugaredLibraryConfiguration.getBackportCoreLibraryMember();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index ee05401..4a3ee89 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -209,6 +209,10 @@
return emulatedInterfaces.containsKey(itf);
}
+ public boolean needsRewriting(DexMethod method) {
+ return emulatedMethods.contains(method.getName());
+ }
+
DexType getEmulatedInterface(DexType itf) {
return emulatedInterfaces.get(itf);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index f172fa9..6f945bd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -27,64 +27,25 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.inliner.InliningIRProvider;
import com.android.tools.r8.ir.optimize.string.StringOptimizer;
-import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import com.google.common.collect.Streams;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
public final class ClassInliner {
enum EligibilityStatus {
- // Used by InlineCandidateProcessor#isInstanceEligible
- NON_CLASS_TYPE,
- NOT_A_SINGLETON_FIELD,
- RETRIEVAL_MAY_HAVE_SIDE_EFFECTS,
- UNKNOWN_TYPE,
- UNUSED_INSTANCE,
-
- // Used by isClassEligible
- NON_PROGRAM_CLASS,
- ABSTRACT_OR_INTERFACE,
- NEVER_CLASS_INLINE,
- IS_PINNED_TYPE,
- HAS_FINALIZER,
- TRIGGER_CLINIT,
-
- // Used by InlineCandidateProcessor#isClassAndUsageEligible
- HAS_CLINIT,
- HAS_INSTANCE_FIELDS,
- NON_FINAL_TYPE,
- NOT_INITIALIZED_AT_INIT,
- PINNED_FIELD,
-
- ELIGIBLE
+ ELIGIBLE,
+ NOT_ELIGIBLE
}
private final ConcurrentHashMap<DexClass, EligibilityStatus> knownClasses =
new ConcurrentHashMap<>();
- private void logEligibilityStatus(
- DexEncodedMethod context, Instruction root, EligibilityStatus status) {
- if (Log.ENABLED && Log.isLoggingEnabledFor(ClassInliner.class)) {
- Log.info(getClass(), "At %s,", context.toSourceString());
- Log.info(getClass(), "ClassInlining eligibility of `%s`: %s.", root, status);
- }
- }
-
- private void logIneligibleUser(
- DexEncodedMethod context, Instruction root, InstructionOrPhi ineligibleUser) {
- if (Log.ENABLED && Log.isLoggingEnabledFor(ClassInliner.class)) {
- Log.info(getClass(), "At %s,", context.toSourceString());
- Log.info(getClass(), "Ineligible user of `%s`: `%s`.", root, ineligibleUser);
- }
- }
-
// Process method code and inline eligible class instantiations, in short:
//
// - collect all 'new-instance' and 'static-get' instructions (called roots below) in
@@ -176,9 +137,7 @@
// Collect all the new-instance and static-get instructions in the code before inlining.
List<Instruction> roots =
- Streams.stream(code.instructionIterator())
- .filter(insn -> insn.isNewInstance() || insn.isStaticGet())
- .collect(Collectors.toList());
+ Lists.newArrayList(code.instructions(insn -> insn.isNewInstance() || insn.isStaticGet()));
// We loop inlining iterations until there was no inlining, but still use same set
// of roots to avoid infinite inlining. Looping makes possible for some roots to
@@ -204,13 +163,11 @@
// Assess eligibility of instance and class.
EligibilityStatus status = processor.isInstanceEligible();
if (status != EligibilityStatus.ELIGIBLE) {
- logEligibilityStatus(code.method(), root, status);
// This root will never be inlined.
rootsIterator.remove();
continue;
}
status = processor.isClassAndUsageEligible();
- logEligibilityStatus(code.method(), root, status);
if (status != EligibilityStatus.ELIGIBLE) {
// This root will never be inlined.
rootsIterator.remove();
@@ -221,7 +178,6 @@
InstructionOrPhi ineligibleUser = processor.areInstanceUsersEligible(defaultOracle);
if (ineligibleUser != null) {
// This root may succeed if users change in future.
- logIneligibleUser(code.method(), root, ineligibleUser);
continue;
}
@@ -309,7 +265,8 @@
}
}
- private EligibilityStatus isClassEligible(AppView<AppInfoWithLiveness> appView, DexClass clazz) {
+ private EligibilityStatus isClassEligible(
+ AppView<AppInfoWithLiveness> appView, DexProgramClass clazz) {
EligibilityStatus eligible = knownClasses.get(clazz);
if (eligible == null) {
EligibilityStatus computed = computeClassEligible(appView, clazz);
@@ -325,21 +282,12 @@
// - does not declare finalizer
// - does not trigger any static initializers except for its own
private EligibilityStatus computeClassEligible(
- AppView<AppInfoWithLiveness> appView, DexClass clazz) {
- if (clazz == null) {
- return EligibilityStatus.UNKNOWN_TYPE;
- }
- if (clazz.isNotProgramClass()) {
- return EligibilityStatus.NON_PROGRAM_CLASS;
- }
- if (clazz.isAbstract() || clazz.isInterface()) {
- return EligibilityStatus.ABSTRACT_OR_INTERFACE;
- }
- if (appView.appInfo().neverClassInline.contains(clazz.type)) {
- return EligibilityStatus.NEVER_CLASS_INLINE;
- }
- if (appView.appInfo().isPinned(clazz.type)) {
- return EligibilityStatus.IS_PINNED_TYPE;
+ AppView<AppInfoWithLiveness> appView, DexProgramClass clazz) {
+ if (clazz == null
+ || clazz.isAbstract()
+ || clazz.isInterface()
+ || !appView.appInfo().isClassInliningAllowed(clazz)) {
+ return EligibilityStatus.NOT_ELIGIBLE;
}
// Class must not define finalizer.
@@ -347,13 +295,13 @@
for (DexEncodedMethod method : clazz.virtualMethods()) {
if (method.method.name == dexItemFactory.finalizeMethodName
&& method.method.proto == dexItemFactory.objectMembers.finalize.proto) {
- return EligibilityStatus.HAS_FINALIZER;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
}
// Check for static initializers in this class or any of interfaces it implements.
if (clazz.initializationOfParentTypesMayHaveSideEffects(appView)) {
- return EligibilityStatus.TRIGGER_CLINIT;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
return EligibilityStatus.ELIGIBLE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index b917507..c8cc00e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AccessControl;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -95,7 +94,7 @@
private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory dexItemFactory;
private final Inliner inliner;
- private final Function<DexClass, EligibilityStatus> isClassEligible;
+ private final Function<DexProgramClass, EligibilityStatus> isClassEligible;
private final MethodProcessor methodProcessor;
private final ProgramMethod method;
private final Instruction root;
@@ -122,7 +121,7 @@
InlineCandidateProcessor(
AppView<AppInfoWithLiveness> appView,
Inliner inliner,
- Function<DexClass, EligibilityStatus> isClassEligible,
+ Function<DexProgramClass, EligibilityStatus> isClassEligible,
MethodProcessor methodProcessor,
ProgramMethod method,
Instruction root) {
@@ -157,20 +156,20 @@
EligibilityStatus isInstanceEligible() {
eligibleInstance = root.outValue();
if (eligibleInstance == null) {
- return EligibilityStatus.UNUSED_INSTANCE;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
if (root.isNewInstance()) {
eligibleClass = asProgramClassOrNull(appView.definitionFor(root.asNewInstance().clazz));
if (eligibleClass == null) {
- return EligibilityStatus.UNKNOWN_TYPE;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
if (eligibleClass.classInitializationMayHaveSideEffects(
appView,
// Types that are a super type of the current context are guaranteed to be initialized.
type -> appView.isSubtype(method.getHolderType(), type).isTrue(),
Sets.newIdentityHashSet())) {
- return EligibilityStatus.HAS_CLINIT;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
return EligibilityStatus.ELIGIBLE;
}
@@ -179,19 +178,19 @@
StaticGet staticGet = root.asStaticGet();
if (staticGet.instructionMayHaveSideEffects(appView, method)) {
- return EligibilityStatus.RETRIEVAL_MAY_HAVE_SIDE_EFFECTS;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
DexEncodedField field = appView.appInfo().resolveField(staticGet.getField()).getResolvedField();
FieldOptimizationInfo optimizationInfo = field.getOptimizationInfo();
ClassTypeElement dynamicLowerBoundType = optimizationInfo.getDynamicLowerBoundType();
if (dynamicLowerBoundType == null
|| !dynamicLowerBoundType.equals(optimizationInfo.getDynamicUpperBoundType())) {
- return EligibilityStatus.NOT_A_SINGLETON_FIELD;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
eligibleClass =
asProgramClassOrNull(appView.definitionFor(dynamicLowerBoundType.getClassType()));
if (eligibleClass == null) {
- return EligibilityStatus.UNKNOWN_TYPE;
+ return EligibilityStatus.NOT_ELIGIBLE;
}
return EligibilityStatus.ELIGIBLE;
}
@@ -313,7 +312,7 @@
if (AccessControl.isClassAccessible(singleTarget.getHolder(), method, appView)
.isPossiblyFalse()) {
- continue;
+ return user; // Not eligible.
}
// Eligible constructor call (for new instance roots only).
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index 9d4121c..fb120e0 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -5,7 +5,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexClassAndField;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
@@ -48,7 +49,7 @@
}
private DexMethod validTargetFor(DexMethod target, DexMethod original) {
- DexClass clazz = appView.definitionFor(target.holder);
+ DexClass clazz = appView.definitionFor(target.getHolderType());
assert clazz != null;
if (clazz.isProgramClass()) {
return target;
@@ -56,36 +57,38 @@
DexType newHolder;
if (clazz.isInterface()) {
newHolder =
- firstLibraryClassForInterfaceTarget(target, original.holder, DexClass::lookupMethod);
+ firstLibraryClassForInterfaceTarget(
+ appView, target, original.holder, DexClass::lookupMethod);
} else {
- newHolder = firstLibraryClass(target.holder, original.holder);
+ newHolder = firstLibraryClass(appView, target.getHolderType(), original.getHolderType());
}
return newHolder == null
? original
: appView.dexItemFactory().createMethod(newHolder, original.proto, original.name);
}
- private DexField validTargetFor(DexField target, DexField original,
- BiFunction<DexClass, DexField, DexEncodedField> lookup) {
- DexClass clazz = appView.definitionFor(target.holder);
- assert clazz != null;
- if (clazz.isProgramClass()) {
- return target;
+ public static DexField validMemberRebindingTargetFor(
+ DexDefinitionSupplier definitions, DexClassAndField field, DexField original) {
+ DexClass clazz = field.getHolder();
+ if (field.isProgramField()) {
+ return field.getReference();
}
- DexType newHolder;
- if (clazz.isInterface()) {
- newHolder = firstLibraryClassForInterfaceTarget(target, original.holder, lookup);
- } else {
- newHolder = firstLibraryClass(target.holder, original.holder);
- }
- return newHolder == null
- ? original
- : appView.dexItemFactory().createField(newHolder, original.type, original.name);
+ DexType newHolder =
+ clazz.isInterface()
+ ? firstLibraryClassForInterfaceTarget(
+ definitions, field.getReference(), original.getHolderType(), DexClass::lookupField)
+ : firstLibraryClass(definitions, field.getHolderType(), original.getHolderType());
+ return newHolder != null
+ ? field.getReference().withHolder(newHolder, definitions.dexItemFactory())
+ : original;
}
- private <T> DexType firstLibraryClassForInterfaceTarget(T target, DexType current,
+ private static <T> DexType firstLibraryClassForInterfaceTarget(
+ DexDefinitionSupplier definitions,
+ T target,
+ DexType current,
BiFunction<DexClass, T, ?> lookup) {
- DexClass clazz = appView.definitionFor(current);
+ DexClass clazz = definitions.definitionFor(current);
if (clazz == null) {
return null;
}
@@ -95,14 +98,16 @@
return current;
}
if (clazz.superType != null) {
- DexType matchingSuper = firstLibraryClassForInterfaceTarget(target, clazz.superType, lookup);
+ DexType matchingSuper =
+ firstLibraryClassForInterfaceTarget(definitions, target, clazz.superType, lookup);
if (matchingSuper != null) {
// Found in supertype, return first library class.
return clazz.isNotProgramClass() ? current : matchingSuper;
}
}
for (DexType iface : clazz.interfaces.values) {
- DexType matchingIface = firstLibraryClassForInterfaceTarget(target, iface, lookup);
+ DexType matchingIface =
+ firstLibraryClassForInterfaceTarget(definitions, target, iface, lookup);
if (matchingIface != null) {
// Found in interface, return first library class.
return clazz.isNotProgramClass() ? current : matchingIface;
@@ -111,11 +116,12 @@
return null;
}
- private DexType firstLibraryClass(DexType top, DexType bottom) {
- assert appView.definitionFor(top).isNotProgramClass();
- DexClass searchClass = appView.definitionFor(bottom);
+ private static DexType firstLibraryClass(
+ DexDefinitionSupplier definitions, DexType top, DexType bottom) {
+ assert definitions.definitionFor(top).isNotProgramClass();
+ DexClass searchClass = definitions.definitionFor(bottom);
while (searchClass.isProgramClass()) {
- searchClass = appView.definitionFor(searchClass.superType);
+ searchClass = definitions.definitionFor(searchClass.superType);
}
return searchClass.type;
}
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
index 8820838..a5a77d7 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
@@ -241,7 +241,6 @@
for (DexProgramClass clazz : synthesizedFrom) {
// TODO(b/165783399): What do we want to put here if the class that this was synthesized from
// is no longer in the application?
- assert appView.definitionFor(clazz.type) != null;
DexProgramClass newClass =
newProgramClasses.computeIfAbsent(clazz.getType(), ignore -> fixupClass(clazz));
newSynthesizedFrom.add(newClass);
diff --git a/src/main/java/com/android/tools/r8/retrace/Result.java b/src/main/java/com/android/tools/r8/retrace/Result.java
deleted file mode 100644
index 692ca9b..0000000
--- a/src/main/java/com/android/tools/r8/retrace/Result.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2019, 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.retrace;
-
-import com.android.tools.r8.Keep;
-import java.util.function.Consumer;
-import java.util.stream.Stream;
-
-@Keep
-public abstract class Result<R, RR extends Result<R, RR>> {
-
- public abstract Stream<R> stream();
-
- public abstract RR forEach(Consumer<R> resultConsumer);
-
- public abstract boolean isAmbiguous();
-}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index b8d94e6..9b838df 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -12,6 +12,13 @@
import com.android.tools.r8.Version;
import com.android.tools.r8.retrace.RetraceCommand.Builder;
import com.android.tools.r8.retrace.RetraceCommand.ProguardMapProducer;
+import com.android.tools.r8.retrace.internal.PlainStackTraceVisitor;
+import com.android.tools.r8.retrace.internal.RetraceAbortException;
+import com.android.tools.r8.retrace.internal.RetraceCommandLineResult;
+import com.android.tools.r8.retrace.internal.RetraceRegularExpression;
+import com.android.tools.r8.retrace.internal.RetracerImpl;
+import com.android.tools.r8.retrace.internal.StackTraceElementProxyRetracerImpl;
+import com.android.tools.r8.retrace.internal.StackTraceElementStringProxy;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.OptionsParsing;
import com.android.tools.r8.utils.OptionsParsing.ParseContext;
@@ -157,8 +164,8 @@
try {
Timing timing = Timing.create("R8 retrace", command.printMemory());
timing.begin("Read proguard map");
- RetraceApi retracer =
- Retracer.create(command.proguardMapProducer, command.diagnosticsHandler);
+ RetracerImpl retracer =
+ RetracerImpl.create(command.proguardMapProducer, command.diagnosticsHandler);
timing.end();
RetraceCommandLineResult result;
timing.begin("Parse and Retrace");
@@ -175,7 +182,7 @@
PlainStackTraceVisitor plainStackTraceVisitor =
new PlainStackTraceVisitor(command.stackTrace, command.diagnosticsHandler);
StackTraceElementProxyRetracer<StackTraceElementStringProxy> proxyRetracer =
- new StackTraceElementProxyRetracer<>(retracer);
+ new StackTraceElementProxyRetracerImpl<>(retracer);
List<String> retracedStrings = new ArrayList<>();
plainStackTraceVisitor.forEach(
stackTraceElement -> {
@@ -274,8 +281,6 @@
return readLines;
}
- static class RetraceAbortException extends RuntimeException {}
-
private interface MainAction {
void run() throws RetraceAbortException;
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceApi.java b/src/main/java/com/android/tools/r8/retrace/RetraceApi.java
deleted file mode 100644
index 7a1eb4e..0000000
--- a/src/main/java/com/android/tools/r8/retrace/RetraceApi.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2019, 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.retrace;
-
-import com.android.tools.r8.Keep;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.TypeReference;
-
-/** This is the main api interface for retrace. */
-@Keep
-public interface RetraceApi {
-
- // TODO(b/170711681): Rename these to not have overloads.
-
- RetraceClassResult retrace(ClassReference classReference);
-
- RetraceMethodResult retrace(MethodReference methodReference);
-
- RetraceFieldResult retrace(FieldReference fieldReference);
-
- RetraceFrameResult retrace(MethodReference methodReference, int position);
-
- RetraceTypeResult retrace(TypeReference typeReference);
-}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassMemberElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassMemberElement.java
deleted file mode 100644
index c21a100..0000000
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassMemberElement.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2020, 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.retrace;
-
-import java.util.function.BiConsumer;
-
-public interface RetraceClassMemberElement<T extends RetracedClassMember> {
-
- boolean isUnknown();
-
- default boolean isFrameElement() {
- return false;
- }
-
- default RetraceFrameResult.Element asFrameElement() {
- return null;
- }
-
- RetraceClassResult.Element getClassElement();
-
- T getMember();
-
- void visitFrames(BiConsumer<T, Integer> consumer);
-
- RetraceSourceFileResult retraceSourceFile(RetracedClassMember frame, String sourceFile);
-}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
index 795311e..f9d0d6f 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
@@ -1,244 +1,58 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.retrace;
-import static com.android.tools.r8.naming.MemberNaming.NoSignature.NO_SIGNATURE;
-import static com.android.tools.r8.retrace.RetraceUtils.synthesizeFileName;
-
import com.android.tools.r8.Keep;
-import com.android.tools.r8.naming.ClassNamingForNameMapper;
-import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
-import com.android.tools.r8.naming.MemberNaming;
-import com.android.tools.r8.naming.mappinginformation.MappingInformation;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.retrace.RetraceClassResult.Element;
-import com.android.tools.r8.utils.Pair;
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
-import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.stream.Stream;
@Keep
-public class RetraceClassResult extends Result<Element, RetraceClassResult> {
+public interface RetraceClassResult {
- private final ClassReference obfuscatedReference;
- private final ClassNamingForNameMapper mapper;
- private final RetraceApi retracer;
+ RetraceFieldResult lookupField(String fieldName);
- private RetraceClassResult(
- ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetraceApi retracer) {
- this.obfuscatedReference = obfuscatedReference;
- this.mapper = mapper;
- this.retracer = retracer;
- }
+ RetraceFieldResult lookupField(String fieldName, TypeReference fieldType);
- static RetraceClassResult create(
- ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetraceApi retracer) {
- return new RetraceClassResult(obfuscatedReference, mapper, retracer);
- }
+ RetraceMethodResult lookupMethod(String methodName);
- public RetraceFieldResult lookupField(String fieldName) {
- return lookupField(FieldDefinition.create(obfuscatedReference, fieldName));
- }
+ RetraceMethodResult lookupMethod(
+ String methodName, List<TypeReference> formalTypes, TypeReference returnType);
- public RetraceFieldResult lookupField(String fieldName, TypeReference fieldType) {
- return lookupField(
- FieldDefinition.create(Reference.field(obfuscatedReference, fieldName, fieldType)));
- }
+ RetraceFrameResult lookupFrame(String methodName);
- public RetraceMethodResult lookupMethod(String methodName) {
- return lookupMethod(MethodDefinition.create(obfuscatedReference, methodName));
- }
+ RetraceFrameResult lookupFrame(String methodName, int position);
- public RetraceMethodResult lookupMethod(
- String methodName, List<TypeReference> formalTypes, TypeReference returnType) {
- return lookupMethod(
- MethodDefinition.create(
- Reference.method(obfuscatedReference, methodName, formalTypes, returnType)));
- }
+ RetraceFrameResult lookupFrame(
+ String methodName, int position, List<TypeReference> formalTypes, TypeReference returnType);
- private RetraceFieldResult lookupField(FieldDefinition fieldDefinition) {
- return lookup(
- fieldDefinition,
- (mapper, name) -> {
- List<MemberNaming> memberNamings = mapper.mappedFieldNamingsByName.get(name);
- if (memberNamings == null || memberNamings.isEmpty()) {
- return null;
- }
- return memberNamings;
- },
- RetraceFieldResult::new);
- }
+ Stream<Element> stream();
- private RetraceMethodResult lookupMethod(MethodDefinition methodDefinition) {
- return lookup(
- methodDefinition,
- (mapper, name) -> {
- MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(name);
- if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
- return null;
- }
- return mappedRanges.getMappedRanges();
- },
- RetraceMethodResult::new);
- }
+ RetraceClassResult forEach(Consumer<Element> resultConsumer);
- private <T, R, D extends Definition> R lookup(
- D definition,
- BiFunction<ClassNamingForNameMapper, String, T> lookupFunction,
- ResultConstructor<T, R, D> constructor) {
- List<Pair<Element, T>> mappings = new ArrayList<>();
- forEach(
- element -> {
- if (mapper != null) {
- assert element.mapper != null;
- T mappedElements = lookupFunction.apply(element.mapper, definition.getName());
- if (mappedElements != null) {
- mappings.add(new Pair<>(element, mappedElements));
- return;
- }
- }
- mappings.add(new Pair<>(element, null));
- });
- return constructor.create(this, mappings, definition, retracer);
- }
+ boolean isAmbiguous();
- boolean hasRetraceResult() {
- return mapper != null;
- }
+ @Keep
+ interface Element {
- @Override
- public Stream<Element> stream() {
- return Stream.of(
- new Element(
- this,
- RetracedClass.create(
- mapper == null
- ? obfuscatedReference
- : Reference.classFromTypeName(mapper.originalName)),
- mapper));
- }
+ RetracedClass getRetracedClass();
- @Override
- public RetraceClassResult forEach(Consumer<Element> resultConsumer) {
- stream().forEach(resultConsumer);
- return this;
- }
+ RetraceClassResult getRetraceClassResult();
- private interface ResultConstructor<T, R, D> {
- R create(
- RetraceClassResult classResult,
- List<Pair<Element, T>> mappings,
- D definition,
- RetraceApi retraceApi);
- }
+ RetraceSourceFileResult retraceSourceFile(String sourceFile);
- @Override
- public boolean isAmbiguous() {
- // Currently we have no way of producing ambiguous class results.
- return false;
- }
+ RetraceFieldResult lookupField(String fieldName);
- public static class Element {
+ RetraceMethodResult lookupMethod(String methodName);
- private final RetraceClassResult classResult;
- private final RetracedClass classReference;
- private final ClassNamingForNameMapper mapper;
+ RetraceFrameResult lookupFrame(String methodName);
- public Element(
- RetraceClassResult classResult,
- RetracedClass classReference,
- ClassNamingForNameMapper mapper) {
- this.classResult = classResult;
- this.classReference = classReference;
- this.mapper = mapper;
- }
+ RetraceFrameResult lookupFrame(String methodName, int position);
- public RetracedClass getRetracedClass() {
- return classReference;
- }
-
- public RetraceClassResult getRetraceClassResult() {
- return classResult;
- }
-
- public RetraceSourceFileResult retraceSourceFile(String sourceFile) {
- if (mapper != null && mapper.getAdditionalMappings().size() > 0) {
- List<MappingInformation> mappingInformations =
- mapper.getAdditionalMappings().get(NO_SIGNATURE);
- if (mappingInformations != null) {
- for (MappingInformation mappingInformation : mappingInformations) {
- if (mappingInformation.isFileNameInformation()) {
- return new RetraceSourceFileResult(
- mappingInformation.asFileNameInformation().getFileName(), false);
- }
- }
- }
- }
- return new RetraceSourceFileResult(
- synthesizeFileName(
- classReference.getTypeName(),
- classResult.obfuscatedReference.getTypeName(),
- sourceFile,
- mapper != null),
- true);
- }
-
- public RetraceFieldResult lookupField(String fieldName) {
- return lookupField(FieldDefinition.create(classReference.getClassReference(), fieldName));
- }
-
- private RetraceFieldResult lookupField(FieldDefinition fieldDefinition) {
- return lookup(
- fieldDefinition,
- (mapper, name) -> {
- List<MemberNaming> memberNamings = mapper.mappedFieldNamingsByName.get(name);
- if (memberNamings == null || memberNamings.isEmpty()) {
- return null;
- }
- return memberNamings;
- },
- RetraceFieldResult::new);
- }
-
- public RetraceMethodResult lookupMethod(String methodName) {
- return lookupMethod(MethodDefinition.create(classReference.getClassReference(), methodName));
- }
-
- private RetraceMethodResult lookupMethod(MethodDefinition methodDefinition) {
- return lookup(
- methodDefinition,
- (mapper, name) -> {
- MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(name);
- if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
- return null;
- }
- return mappedRanges.getMappedRanges();
- },
- RetraceMethodResult::new);
- }
-
- private <T, R, D extends Definition> R lookup(
- D definition,
- BiFunction<ClassNamingForNameMapper, String, T> lookupFunction,
- ResultConstructor<T, R, D> constructor) {
- List<Pair<Element, T>> mappings = ImmutableList.of();
- if (mapper != null) {
- T result = lookupFunction.apply(mapper, definition.getName());
- if (result != null) {
- mappings = ImmutableList.of(new Pair<>(this, result));
- }
- }
- if (mappings.isEmpty()) {
- mappings = ImmutableList.of(new Pair<>(this, null));
- }
- return constructor.create(classResult, mappings, definition, classResult.retracer);
- }
+ RetraceFrameResult lookupFrame(
+ String methodName, int position, List<TypeReference> formalTypes, TypeReference returnType);
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
index 46f247d..f141080 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
@@ -1,129 +1,31 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.retrace;
import com.android.tools.r8.Keep;
-import com.android.tools.r8.naming.MemberNaming;
-import com.android.tools.r8.naming.MemberNaming.FieldSignature;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.Pair;
-import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
@Keep
-public class RetraceFieldResult extends Result<RetraceFieldResult.Element, RetraceFieldResult> {
+public interface RetraceFieldResult {
- private final RetraceClassResult classResult;
- private final List<Pair<RetraceClassResult.Element, List<MemberNaming>>> memberNamings;
- private final FieldDefinition fieldDefinition;
- private final RetraceApi retracer;
+ Stream<Element> stream();
- RetraceFieldResult(
- RetraceClassResult classResult,
- List<Pair<RetraceClassResult.Element, List<MemberNaming>>> memberNamings,
- FieldDefinition fieldDefinition,
- RetraceApi retracer) {
- this.classResult = classResult;
- this.memberNamings = memberNamings;
- this.fieldDefinition = fieldDefinition;
- this.retracer = retracer;
- assert classResult != null;
- assert !memberNamings.isEmpty();
- }
+ RetraceFieldResult forEach(Consumer<Element> resultConsumer);
- @Override
- public boolean isAmbiguous() {
- if (memberNamings.size() > 1) {
- return true;
- }
- List<MemberNaming> mappings = memberNamings.get(0).getSecond();
- if (mappings == null) {
- return false;
- }
- return mappings.size() > 1;
- }
+ boolean isAmbiguous();
- @Override
- public Stream<Element> stream() {
- return memberNamings.stream()
- .flatMap(
- mappedNamePair -> {
- RetraceClassResult.Element classElement = mappedNamePair.getFirst();
- List<MemberNaming> memberNamings = mappedNamePair.getSecond();
- if (memberNamings == null) {
- return Stream.of(
- new RetraceFieldResult.Element(
- this,
- classElement,
- RetracedField.create(
- fieldDefinition.substituteHolder(
- classElement.getRetracedClass().getClassReference()))));
- }
- return memberNamings.stream()
- .map(
- memberNaming -> {
- FieldSignature fieldSignature =
- memberNaming.getOriginalSignature().asFieldSignature();
- RetracedClass holder =
- fieldSignature.isQualified()
- ? RetracedClass.create(
- Reference.classFromDescriptor(
- DescriptorUtils.javaTypeToDescriptor(
- fieldSignature.toHolderFromQualified())))
- : classElement.getRetracedClass();
- return new Element(
- this,
- classElement,
- RetracedField.create(
- Reference.field(
- holder.getClassReference(),
- fieldSignature.isQualified()
- ? fieldSignature.toUnqualifiedName()
- : fieldSignature.name,
- Reference.typeFromTypeName(fieldSignature.type))));
- });
- });
- }
+ @Keep
+ interface Element {
- @Override
- public RetraceFieldResult forEach(Consumer<Element> resultConsumer) {
- stream().forEach(resultConsumer);
- return this;
- }
+ boolean isUnknown();
- public static class Element {
+ RetracedField getField();
- private final RetracedField fieldReference;
- private final RetraceFieldResult retraceFieldResult;
- private final RetraceClassResult.Element classElement;
+ RetraceFieldResult getRetraceFieldResult();
- private Element(
- RetraceFieldResult retraceFieldResult,
- RetraceClassResult.Element classElement,
- RetracedField fieldReference) {
- this.classElement = classElement;
- this.fieldReference = fieldReference;
- this.retraceFieldResult = retraceFieldResult;
- }
-
- public boolean isUnknown() {
- return fieldReference.isUnknown();
- }
-
- public RetracedField getField() {
- return fieldReference;
- }
-
- public RetraceFieldResult getRetraceFieldResult() {
- return retraceFieldResult;
- }
-
- public RetraceClassResult.Element getClassElement() {
- return classElement;
- }
+ RetraceClassResult.Element getClassElement();
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFrameResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceFrameResult.java
index 95dc9d5..b439d94 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFrameResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFrameResult.java
@@ -4,161 +4,34 @@
package com.android.tools.r8.retrace;
-import static com.android.tools.r8.retrace.RetraceUtils.methodReferenceFromMappedRange;
-
-import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.utils.Pair;
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.Collections;
+import com.android.tools.r8.Keep;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Stream;
-public class RetraceFrameResult extends Result<RetraceFrameResult.Element, RetraceFrameResult> {
+@Keep
+public interface RetraceFrameResult {
- private final RetraceClassResult classResult;
- private final MethodDefinition methodDefinition;
- private final int obfuscatedPosition;
- private final List<Pair<RetraceClassResult.Element, List<MappedRange>>> mappedRanges;
- private final RetraceApi retracer;
+ Stream<Element> stream();
- public RetraceFrameResult(
- RetraceClassResult classResult,
- List<Pair<RetraceClassResult.Element, List<MappedRange>>> mappedRanges,
- MethodDefinition methodDefinition,
- int obfuscatedPosition,
- RetraceApi retracer) {
- this.classResult = classResult;
- this.methodDefinition = methodDefinition;
- this.obfuscatedPosition = obfuscatedPosition;
- this.mappedRanges = mappedRanges;
- this.retracer = retracer;
- }
+ RetraceFrameResult forEach(Consumer<Element> resultConsumer);
- @Override
- public boolean isAmbiguous() {
- return mappedRanges.size() > 1;
- }
+ boolean isAmbiguous();
- @Override
- public Stream<Element> stream() {
- return mappedRanges.stream()
- .map(
- mappedRangePair -> {
- RetraceClassResult.Element classElement = mappedRangePair.getFirst();
- List<MappedRange> mappedRanges = mappedRangePair.getSecond();
- if (mappedRanges == null || mappedRanges.isEmpty()) {
- return new Element(
- this,
- classElement,
- RetracedMethod.create(
- methodDefinition.substituteHolder(
- classElement.getRetracedClass().getClassReference())),
- ImmutableList.of(),
- obfuscatedPosition);
- }
- MappedRange mappedRange = mappedRanges.get(0);
- MethodReference methodReference =
- methodReferenceFromMappedRange(
- mappedRange, classElement.getRetracedClass().getClassReference());
- RetracedMethod retracedMethod =
- RetracedMethod.create(
- methodReference, mappedRange.getOriginalLineNumber(obfuscatedPosition));
- return new Element(
- this, classElement, retracedMethod, mappedRanges, obfuscatedPosition);
- });
- }
+ @Keep
+ interface Element {
- @Override
- public RetraceFrameResult forEach(Consumer<Element> resultConsumer) {
- stream().forEach(resultConsumer);
- return this;
- }
+ boolean isUnknown();
- public static class Element implements RetraceClassMemberElement<RetracedMethod> {
+ RetracedMethod getTopFrame();
- private final RetracedMethod methodReference;
- private final RetraceFrameResult retraceFrameResult;
- private final RetraceClassResult.Element classElement;
- private final List<MappedRange> mappedRanges;
- private final int obfuscatedPosition;
+ RetraceClassResult.Element getClassElement();
- public Element(
- RetraceFrameResult retraceFrameResult,
- RetraceClassResult.Element classElement,
- RetracedMethod methodReference,
- List<MappedRange> mappedRanges,
- int obfuscatedPosition) {
- this.methodReference = methodReference;
- this.retraceFrameResult = retraceFrameResult;
- this.classElement = classElement;
- this.mappedRanges = mappedRanges;
- this.obfuscatedPosition = obfuscatedPosition;
- }
+ void visitFrames(BiConsumer<RetracedMethod, Integer> consumer);
- @Override
- public boolean isUnknown() {
- return methodReference.isUnknown();
- }
+ RetraceSourceFileResult retraceSourceFile(RetracedClassMember frame, String sourceFile);
- @Override
- public boolean isFrameElement() {
- return true;
- }
-
- @Override
- public Element asFrameElement() {
- return this;
- }
-
- @Override
- public RetracedMethod getMember() {
- return methodReference;
- }
-
- public RetracedMethod getTopFrame() {
- return methodReference;
- }
-
- @Override
- public RetraceClassResult.Element getClassElement() {
- return classElement;
- }
-
- @Override
- public void visitFrames(BiConsumer<RetracedMethod, Integer> consumer) {
- int counter = 0;
- consumer.accept(methodReference, counter++);
- for (RetracedMethod outerFrame : getOuterFrames()) {
- consumer.accept(outerFrame, counter++);
- }
- }
-
- @Override
- public RetraceSourceFileResult retraceSourceFile(RetracedClassMember frame, String sourceFile) {
- return RetraceUtils.getSourceFile(
- classElement, frame.getHolderClass(), sourceFile, retraceFrameResult.retracer);
- }
-
- public List<RetracedMethod> getOuterFrames() {
- if (mappedRanges == null) {
- return Collections.emptyList();
- }
- List<RetracedMethod> outerFrames = new ArrayList<>();
- for (int i = 1; i < mappedRanges.size(); i++) {
- MappedRange mappedRange = mappedRanges.get(i);
- MethodReference methodReference =
- methodReferenceFromMappedRange(
- mappedRange, classElement.getRetracedClass().getClassReference());
- outerFrames.add(
- RetracedMethod.create(
- MethodDefinition.create(methodReference),
- mappedRange.getOriginalLineNumber(obfuscatedPosition)));
- }
- return outerFrames;
- }
+ List<? extends RetracedMethod> getOuterFrames();
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
index 0906420..20c73e3 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
@@ -1,174 +1,35 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.retrace;
import com.android.tools.r8.Keep;
-import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
-import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.utils.Pair;
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Stream;
@Keep
-public class RetraceMethodResult extends Result<RetraceMethodResult.Element, RetraceMethodResult> {
+public interface RetraceMethodResult {
- private final MethodDefinition methodDefinition;
- private final RetraceClassResult classResult;
- private final List<Pair<RetraceClassResult.Element, List<MappedRange>>> mappedRanges;
- private final RetraceApi retracer;
+ RetraceFrameResult narrowByPosition(int position);
- RetraceMethodResult(
- RetraceClassResult classResult,
- List<Pair<RetraceClassResult.Element, List<MappedRange>>> mappedRanges,
- MethodDefinition methodDefinition,
- RetraceApi retracer) {
- this.classResult = classResult;
- this.mappedRanges = mappedRanges;
- this.methodDefinition = methodDefinition;
- this.retracer = retracer;
- assert classResult != null;
- assert !mappedRanges.isEmpty();
- }
+ Stream<Element> stream();
- @Override
- public boolean isAmbiguous() {
- if (mappedRanges.size() > 1) {
- return true;
- }
- List<MappedRange> methodRanges = mappedRanges.get(0).getSecond();
- if (methodRanges == null || methodRanges.isEmpty()) {
- return false;
- }
- MappedRange lastRange = methodRanges.get(0);
- for (MappedRange mappedRange : methodRanges) {
- if (mappedRange != lastRange
- && (mappedRange.minifiedRange == null
- || !mappedRange.minifiedRange.equals(lastRange.minifiedRange))) {
- return true;
- }
- }
- return false;
- }
+ RetraceMethodResult forEach(Consumer<Element> resultConsumer);
- public RetraceFrameResult narrowByPosition(int position) {
- List<Pair<RetraceClassResult.Element, List<MappedRange>>> narrowedRanges = new ArrayList<>();
- List<Pair<RetraceClassResult.Element, List<MappedRange>>> noMappingRanges = new ArrayList<>();
- for (Pair<RetraceClassResult.Element, List<MappedRange>> mappedRange : mappedRanges) {
- if (mappedRange.getSecond() == null) {
- noMappingRanges.add(new Pair<>(mappedRange.getFirst(), null));
- continue;
- }
- List<MappedRange> ranges =
- new MappedRangesOfName(mappedRange.getSecond()).allRangesForLine(position, false);
- boolean hasAddedRanges = false;
- if (!ranges.isEmpty()) {
- narrowedRanges.add(new Pair<>(mappedRange.getFirst(), ranges));
- hasAddedRanges = true;
- } else {
- narrowedRanges = new ArrayList<>();
- for (MappedRange mapped : mappedRange.getSecond()) {
- if (mapped.minifiedRange == null) {
- narrowedRanges.add(new Pair<>(mappedRange.getFirst(), ImmutableList.of(mapped)));
- hasAddedRanges = true;
- }
- }
- }
- if (!hasAddedRanges) {
- narrowedRanges.add(new Pair<>(mappedRange.getFirst(), null));
- }
- }
- return new RetraceFrameResult(
- classResult,
- narrowedRanges.isEmpty() ? noMappingRanges : narrowedRanges,
- methodDefinition,
- position,
- retracer);
- }
+ boolean isAmbiguous();
- @Override
- public Stream<Element> stream() {
- return mappedRanges.stream()
- .flatMap(
- mappedRangePair -> {
- RetraceClassResult.Element classElement = mappedRangePair.getFirst();
- List<MappedRange> mappedRanges = mappedRangePair.getSecond();
- if (mappedRanges == null || mappedRanges.isEmpty()) {
- return Stream.of(
- new Element(
- this,
- classElement,
- RetracedMethod.create(
- methodDefinition.substituteHolder(
- classElement.getRetracedClass().getClassReference()))));
- }
- return mappedRanges.stream()
- .map(
- mappedRange -> {
- MethodReference methodReference =
- RetraceUtils.methodReferenceFromMappedRange(
- mappedRange, classElement.getRetracedClass().getClassReference());
- return new Element(
- this, classElement, RetracedMethod.create(methodReference));
- });
- });
- }
+ @Keep
+ interface Element {
- @Override
- public RetraceMethodResult forEach(Consumer<Element> resultConsumer) {
- stream().forEach(resultConsumer);
- return this;
- }
+ boolean isUnknown();
- public static class Element implements RetraceClassMemberElement<RetracedMethod> {
+ RetracedMethod getRetracedMethod();
- private final RetracedMethod methodReference;
- private final RetraceMethodResult retraceMethodResult;
- private final RetraceClassResult.Element classElement;
+ RetraceMethodResult getRetraceMethodResult();
- private Element(
- RetraceMethodResult retraceMethodResult,
- RetraceClassResult.Element classElement,
- RetracedMethod methodReference) {
- this.classElement = classElement;
- this.retraceMethodResult = retraceMethodResult;
- this.methodReference = methodReference;
- }
+ RetraceClassResult.Element getClassElement();
- @Override
- public boolean isUnknown() {
- return methodReference.isUnknown();
- }
-
- @Override
- public RetracedMethod getMember() {
- return methodReference;
- }
-
- public RetraceMethodResult getRetraceMethodResult() {
- return retraceMethodResult;
- }
-
- @Override
- public RetraceClassResult.Element getClassElement() {
- return classElement;
- }
-
- @Override
- public void visitFrames(BiConsumer<RetracedMethod, Integer> consumer) {
- consumer.accept(methodReference, 0);
- }
-
- @Override
- public RetraceSourceFileResult retraceSourceFile(RetracedClassMember frame, String sourceFile) {
- return RetraceUtils.getSourceFile(
- classElement, methodReference.getHolderClass(), sourceFile, retraceMethodResult.retracer);
- }
+ RetraceSourceFileResult retraceSourceFile(String sourceFile);
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceSourceFileResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceSourceFileResult.java
index e68e5c9..b2d4273 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceSourceFileResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceSourceFileResult.java
@@ -7,21 +7,9 @@
import com.android.tools.r8.Keep;
@Keep
-public class RetraceSourceFileResult {
+public interface RetraceSourceFileResult {
- private final String filename;
- private final boolean synthesized;
+ boolean isSynthesized();
- RetraceSourceFileResult(String filename, boolean synthesized) {
- this.filename = filename;
- this.synthesized = synthesized;
- }
-
- public boolean isSynthesized() {
- return synthesized;
- }
-
- public String getFilename() {
- return filename;
- }
+ String getFilename();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceProxy.java b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceProxy.java
new file mode 100644
index 0000000..b69c237
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceProxy.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2020, 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.retrace;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface RetraceStackTraceProxy<T extends StackTraceElementProxy<?>> {
+
+ boolean isAmbiguous();
+
+ boolean hasRetracedClass();
+
+ boolean hasRetracedMethod();
+
+ boolean hasSourceFile();
+
+ boolean hasLineNumber();
+
+ T getOriginalItem();
+
+ RetracedClass getRetracedClass();
+
+ RetracedMethod getRetracedMethod();
+
+ String getSourceFile();
+
+ int getLineNumber();
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java
index d546d11..b9fa2d3 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java
@@ -1,66 +1,26 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.retrace;
-import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.retrace.RetraceTypeResult.Element;
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.retrace.internal.RetracedTypeImpl;
import java.util.function.Consumer;
import java.util.stream.Stream;
-public class RetraceTypeResult extends Result<Element, RetraceTypeResult> {
+@Keep
+public interface RetraceTypeResult {
- private final TypeReference obfuscatedType;
- private final RetraceApi retracer;
+ Stream<Element> stream();
- private RetraceTypeResult(TypeReference obfuscatedType, RetraceApi retracer) {
- this.obfuscatedType = obfuscatedType;
- this.retracer = retracer;
- }
+ RetraceTypeResult forEach(Consumer<Element> resultConsumer);
- static RetraceTypeResult create(TypeReference obfuscatedType, RetraceApi retracer) {
- return new RetraceTypeResult(obfuscatedType, retracer);
- }
+ boolean isAmbiguous();
- @Override
- public Stream<Element> stream() {
- // Handle void and primitive types as single element results.
- if (obfuscatedType == null || obfuscatedType.isPrimitive()) {
- return Stream.of(new Element(RetracedType.create(obfuscatedType)));
- }
- if (obfuscatedType.isArray()) {
- int dimensions = obfuscatedType.asArray().getDimensions();
- return retracer.retrace(obfuscatedType.asArray().getBaseType()).stream()
- .map(
- baseElement ->
- new Element(RetracedType.create(baseElement.retracedType.toArray(dimensions))));
- }
- return retracer.retrace(obfuscatedType.asClass()).stream()
- .map(classElement -> new Element(classElement.getRetracedClass().getRetracedType()));
- }
+ @Keep
+ interface Element {
- @Override
- public boolean isAmbiguous() {
- return false;
- }
-
- @Override
- public RetraceTypeResult forEach(Consumer<Element> resultConsumer) {
- stream().forEach(resultConsumer);
- return this;
- }
-
- public static class Element {
-
- private final RetracedType retracedType;
-
- public Element(RetracedType retracedType) {
- this.retracedType = retracedType;
- }
-
- public RetracedType getType() {
- return retracedType;
- }
+ RetracedTypeImpl getType();
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedClass.java b/src/main/java/com/android/tools/r8/retrace/RetracedClass.java
index af064fc..e66931e 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedClass.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedClass.java
@@ -6,50 +6,16 @@
import com.android.tools.r8.Keep;
import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.retrace.internal.RetracedTypeImpl;
@Keep
-public final class RetracedClass {
+public interface RetracedClass {
- private final ClassReference classReference;
+ String getTypeName();
- private RetracedClass(ClassReference classReference) {
- assert classReference != null;
- this.classReference = classReference;
- }
+ String getBinaryName();
- public static RetracedClass create(ClassReference classReference) {
- return new RetracedClass(classReference);
- }
+ RetracedTypeImpl getRetracedType();
- public String getTypeName() {
- return classReference.getTypeName();
- }
-
- public String getBinaryName() {
- return classReference.getBinaryName();
- }
-
- public RetracedType getRetracedType() {
- return RetracedType.create(classReference);
- }
-
- ClassReference getClassReference() {
- return classReference;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- return classReference.equals(((RetracedClass) o).classReference);
- }
-
- @Override
- public int hashCode() {
- return classReference.hashCode();
- }
+ ClassReference getClassReference();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedClassMember.java b/src/main/java/com/android/tools/r8/retrace/RetracedClassMember.java
index e05be47..10aa77c 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedClassMember.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedClassMember.java
@@ -4,7 +4,11 @@
package com.android.tools.r8.retrace;
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.retrace.internal.RetracedClassImpl;
+
+@Keep
public interface RetracedClassMember {
- RetracedClass getHolderClass();
+ RetracedClassImpl getHolderClass();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedField.java b/src/main/java/com/android/tools/r8/retrace/RetracedField.java
index 132d0c7..2af8c71 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedField.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedField.java
@@ -7,122 +7,23 @@
import com.android.tools.r8.Keep;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.TypeReference;
-import java.util.Objects;
@Keep
-public abstract class RetracedField implements RetracedClassMember {
+public interface RetracedField extends RetracedClassMember {
- private RetracedField() {}
+ boolean isUnknown();
- public boolean isUnknown() {
- return true;
- }
+ boolean isKnown();
- public final boolean isKnown() {
- return !isUnknown();
- }
+ KnownRetracedField asKnown();
- public KnownRetracedField asKnown() {
- return null;
- }
+ String getFieldName();
- public abstract String getFieldName();
+ @Keep
+ interface KnownRetracedField extends RetracedField {
- public static final class KnownRetracedField extends RetracedField {
+ TypeReference getFieldType();
- private final FieldReference fieldReference;
-
- private KnownRetracedField(FieldReference fieldReference) {
- this.fieldReference = fieldReference;
- }
-
- @Override
- public boolean isUnknown() {
- return false;
- }
-
- @Override
- public KnownRetracedField asKnown() {
- return this;
- }
-
- @Override
- public RetracedClass getHolderClass() {
- return RetracedClass.create(fieldReference.getHolderClass());
- }
-
- @Override
- public String getFieldName() {
- return fieldReference.getFieldName();
- }
-
- public TypeReference getFieldType() {
- return fieldReference.getFieldType();
- }
-
- public FieldReference getFieldReference() {
- return fieldReference;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- KnownRetracedField that = (KnownRetracedField) o;
- return fieldReference.equals(that.fieldReference);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(fieldReference);
- }
- }
-
- public static final class UnknownRetracedField extends RetracedField {
-
- private final FieldDefinition fieldDefinition;
-
- private UnknownRetracedField(FieldDefinition fieldDefinition) {
- this.fieldDefinition = fieldDefinition;
- }
-
- @Override
- public RetracedClass getHolderClass() {
- return RetracedClass.create(fieldDefinition.getHolderClass());
- }
-
- @Override
- public String getFieldName() {
- return fieldDefinition.getName();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- UnknownRetracedField that = (UnknownRetracedField) o;
- return fieldDefinition.equals(that.fieldDefinition);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(fieldDefinition);
- }
- }
-
- static RetracedField create(FieldReference fieldReference) {
- return new KnownRetracedField(fieldReference);
- }
-
- static RetracedField create(FieldDefinition fieldDefinition) {
- return new UnknownRetracedField(fieldDefinition);
+ FieldReference getFieldReference();
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedMethod.java b/src/main/java/com/android/tools/r8/retrace/RetracedMethod.java
index 937ded1..bfc95e9 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedMethod.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedMethod.java
@@ -8,165 +8,31 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
@Keep
-public abstract class RetracedMethod implements RetracedClassMember {
+public interface RetracedMethod extends RetracedClassMember {
- private static final int NO_POSITION = -1;
+ boolean isUnknown();
- private RetracedMethod() {}
+ boolean isKnown();
- public boolean isUnknown() {
- return true;
- }
+ KnownRetracedMethod asKnown();
- public final boolean isKnown() {
- return !isUnknown();
- }
+ String getMethodName();
- public KnownRetracedMethod asKnown() {
- return null;
- }
+ boolean hasPosition();
- public abstract String getMethodName();
+ int getOriginalPositionOrDefault(int defaultPosition);
- public abstract boolean hasPosition();
+ @Keep
+ interface KnownRetracedMethod extends RetracedMethod {
- public abstract int getOriginalPositionOrDefault(int defaultPosition);
+ boolean isVoid();
- public static final class KnownRetracedMethod extends RetracedMethod {
+ TypeReference getReturnType();
- private final MethodReference methodReference;
- private final int position;
+ List<TypeReference> getFormalTypes();
- private KnownRetracedMethod(MethodReference methodReference, int position) {
- assert methodReference != null;
- this.methodReference = methodReference;
- this.position = position;
- }
-
- @Override
- public boolean isUnknown() {
- return false;
- }
-
- public boolean isVoid() {
- return methodReference.getReturnType() == null;
- }
-
- @Override
- public KnownRetracedMethod asKnown() {
- return this;
- }
-
- @Override
- public RetracedClass getHolderClass() {
- return RetracedClass.create(methodReference.getHolderClass());
- }
-
- @Override
- public String getMethodName() {
- return methodReference.getMethodName();
- }
-
- @Override
- public boolean hasPosition() {
- return position != NO_POSITION;
- }
-
- @Override
- public int getOriginalPositionOrDefault(int defaultPosition) {
- return hasPosition() ? position : defaultPosition;
- }
-
- public TypeReference getReturnType() {
- assert !isVoid();
- return methodReference.getReturnType();
- }
-
- public List<TypeReference> getFormalTypes() {
- return methodReference.getFormalTypes();
- }
-
- public MethodReference getMethodReference() {
- return methodReference;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- KnownRetracedMethod that = (KnownRetracedMethod) o;
- return position == that.position && methodReference.equals(that.methodReference);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(methodReference, position);
- }
- }
-
- public static final class UnknownRetracedMethod extends RetracedMethod {
-
- private final MethodDefinition methodDefinition;
- private final int position;
-
- private UnknownRetracedMethod(MethodDefinition methodDefinition, int position) {
- this.methodDefinition = methodDefinition;
- this.position = position;
- }
-
- @Override
- public RetracedClass getHolderClass() {
- return RetracedClass.create(methodDefinition.getHolderClass());
- }
-
- @Override
- public String getMethodName() {
- return methodDefinition.getName();
- }
-
- @Override
- public boolean hasPosition() {
- return position != NO_POSITION;
- }
-
- @Override
- public int getOriginalPositionOrDefault(int defaultPosition) {
- return hasPosition() ? position : defaultPosition;
- }
-
- public Optional<MethodReference> getMethodReference() {
- if (!methodDefinition.isFullMethodDefinition()) {
- return Optional.empty();
- }
- return Optional.of(methodDefinition.asFullMethodDefinition().getMethodReference());
- }
- }
-
- static RetracedMethod create(MethodDefinition methodDefinition) {
- return create(methodDefinition, NO_POSITION);
- }
-
- static RetracedMethod create(MethodDefinition methodDefinition, int position) {
- if (methodDefinition.isFullMethodDefinition()) {
- return new KnownRetracedMethod(
- methodDefinition.asFullMethodDefinition().getMethodReference(), position);
- }
- return new UnknownRetracedMethod(methodDefinition, position);
- }
-
- static RetracedMethod create(MethodReference methodReference) {
- return create(methodReference, NO_POSITION);
- }
-
- static RetracedMethod create(MethodReference methodReference, int position) {
- return new KnownRetracedMethod(methodReference, position);
+ MethodReference getMethodReference();
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedType.java b/src/main/java/com/android/tools/r8/retrace/RetracedType.java
index 016c8df..7d5baa1 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedType.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedType.java
@@ -5,53 +5,16 @@
package com.android.tools.r8.retrace;
import com.android.tools.r8.Keep;
-import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
-import java.util.Objects;
@Keep
-public final class RetracedType {
+public interface RetracedType {
- private final TypeReference typeReference;
+ boolean isVoid();
- private RetracedType(TypeReference typeReference) {
- this.typeReference = typeReference;
- }
+ TypeReference toArray(int dimensions);
- static RetracedType create(TypeReference typeReference) {
- return new RetracedType(typeReference);
- }
+ String getTypeName();
- public boolean isVoid() {
- return typeReference == null;
- }
-
- public TypeReference toArray(int dimensions) {
- return Reference.array(typeReference, dimensions);
- }
-
- public String getTypeName() {
- assert !isVoid();
- return typeReference.getTypeName();
- }
-
- public TypeReference getTypeReference() {
- return typeReference;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- return typeReference.equals(((RetracedType) o).typeReference);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(typeReference);
- }
+ TypeReference getTypeReference();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retracer.java b/src/main/java/com/android/tools/r8/retrace/Retracer.java
index 279253c..57b7607 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retracer.java
@@ -4,66 +4,23 @@
package com.android.tools.r8.retrace;
-import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.Keep;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.retrace.RetraceCommand.ProguardMapProducer;
-/** A default implementation for the retrace api using the ClassNameMapper defined in R8. */
+/** This is the main api interface for retrace. */
@Keep
-public class Retracer implements RetraceApi {
+public interface Retracer {
- private final ClassNameMapper classNameMapper;
+ RetraceClassResult retraceClass(ClassReference classReference);
- private Retracer(ClassNameMapper classNameMapper) {
- this.classNameMapper = classNameMapper;
- assert classNameMapper != null;
- }
+ RetraceMethodResult retraceMethod(MethodReference methodReference);
- public static RetraceApi create(
- ProguardMapProducer proguardMapProducer, DiagnosticsHandler diagnosticsHandler) {
- if (proguardMapProducer instanceof DirectClassNameMapperProguardMapProducer) {
- return new Retracer(
- ((DirectClassNameMapperProguardMapProducer) proguardMapProducer).getClassNameMapper());
- }
- try {
- ClassNameMapper classNameMapper =
- ClassNameMapper.mapperFromString(proguardMapProducer.get(), diagnosticsHandler);
- return new Retracer(classNameMapper);
- } catch (Throwable throwable) {
- throw new InvalidMappingFileException(throwable);
- }
- }
+ RetraceFrameResult retraceFrame(MethodReference methodReference, int position);
- @Override
- public RetraceMethodResult retrace(MethodReference methodReference) {
- return retrace(methodReference.getHolderClass()).lookupMethod(methodReference.getMethodName());
- }
+ RetraceFieldResult retraceField(FieldReference fieldReference);
- @Override
- public RetraceFieldResult retrace(FieldReference fieldReference) {
- return retrace(fieldReference.getHolderClass()).lookupField(fieldReference.getFieldName());
- }
-
- @Override
- public RetraceFrameResult retrace(MethodReference methodReference, int position) {
- return retrace(methodReference.getHolderClass())
- .lookupMethod(methodReference.getMethodName())
- .narrowByPosition(position);
- }
-
- @Override
- public RetraceClassResult retrace(ClassReference classReference) {
- return RetraceClassResult.create(
- classReference, classNameMapper.getClassNaming(classReference.getTypeName()), this);
- }
-
- @Override
- public RetraceTypeResult retrace(TypeReference typeReference) {
- return RetraceTypeResult.create(typeReference, this);
- }
+ RetraceTypeResult retraceType(TypeReference typeReference);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java b/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java
index 042b1f8..17d9005 100644
--- a/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java
@@ -5,191 +5,11 @@
package com.android.tools.r8.retrace;
import com.android.tools.r8.Keep;
-import com.android.tools.r8.references.Reference;
-import java.util.ArrayList;
-import java.util.List;
+import com.android.tools.r8.retrace.internal.StackTraceElementProxyRetracerImpl.RetraceStackTraceProxyImpl;
import java.util.stream.Stream;
@Keep
-public class StackTraceElementProxyRetracer<T extends StackTraceElementProxy<?>> {
+public interface StackTraceElementProxyRetracer<T extends StackTraceElementProxy<?>> {
- private final RetraceApi retracer;
-
- public StackTraceElementProxyRetracer(RetraceApi retracer) {
- this.retracer = retracer;
- }
-
- public Stream<RetraceStackTraceProxy<T>> retrace(T element) {
- if (!element.hasClassName()) {
- return Stream.of(RetraceStackTraceProxy.builder(element).build());
- }
- RetraceClassResult classResult =
- retracer.retrace(Reference.classFromTypeName(element.className()));
- List<RetraceStackTraceProxy<T>> retracedProxies = new ArrayList<>();
- if (!element.hasMethodName()) {
- classResult.forEach(
- classElement -> {
- RetraceStackTraceProxy.Builder<T> proxy =
- RetraceStackTraceProxy.builder(element)
- .setRetracedClassElement(classElement.getRetracedClass())
- .setAmbiguous(classResult.isAmbiguous());
- if (element.hasFileName()) {
- proxy.setSourceFile(classElement.retraceSourceFile(element.fileName()).getFilename());
- }
- retracedProxies.add(proxy.build());
- });
- } else {
- RetraceMethodResult retraceMethodResult = classResult.lookupMethod(element.methodName());
- Result<? extends RetraceClassMemberElement<RetracedMethod>, ?> methodResult;
- if (element.hasLineNumber()) {
- methodResult = retraceMethodResult.narrowByPosition(element.lineNumber());
- } else {
- methodResult = retraceMethodResult;
- }
- methodResult.forEach(
- methodElement -> {
- methodElement.visitFrames(
- (frame, index) -> {
- RetraceStackTraceProxy.Builder<T> proxy =
- RetraceStackTraceProxy.builder(element)
- .setRetracedClassElement(frame.getHolderClass())
- .setRetracedMethodElement(frame)
- .setAmbiguous(methodResult.isAmbiguous() && index == 0);
- if (element.hasLineNumber()) {
- proxy.setLineNumber(frame.getOriginalPositionOrDefault(element.lineNumber()));
- }
- if (element.hasFileName()) {
- proxy.setSourceFile(
- methodElement.retraceSourceFile(frame, element.fileName()).getFilename());
- }
- retracedProxies.add(proxy.build());
- });
- });
- }
- return retracedProxies.stream();
- }
-
- @Keep
- public static class RetraceStackTraceProxy<T extends StackTraceElementProxy<?>> {
-
- private final T originalItem;
- private final RetracedClass retracedClass;
- private final RetracedMethod retracedMethod;
- private final String sourceFile;
- private final int lineNumber;
- private final boolean isAmbiguous;
-
- private RetraceStackTraceProxy(
- T originalItem,
- RetracedClass retracedClass,
- RetracedMethod retracedMethod,
- String sourceFile,
- int lineNumber,
- boolean isAmbiguous) {
- assert originalItem != null;
- this.originalItem = originalItem;
- this.retracedClass = retracedClass;
- this.retracedMethod = retracedMethod;
- this.sourceFile = sourceFile;
- this.lineNumber = lineNumber;
- this.isAmbiguous = isAmbiguous;
- }
-
- public boolean isAmbiguous() {
- return isAmbiguous;
- }
-
- public boolean hasRetracedClass() {
- return retracedClass != null;
- }
-
- public boolean hasRetracedMethod() {
- return retracedMethod != null;
- }
-
- public boolean hasSourceFile() {
- return sourceFile != null;
- }
-
- public boolean hasLineNumber() {
- return lineNumber != -1;
- }
-
- public T getOriginalItem() {
- return originalItem;
- }
-
- public RetracedClass getRetracedClass() {
- return retracedClass;
- }
-
- public RetracedMethod getRetracedMethod() {
- return retracedMethod;
- }
-
- public String getSourceFile() {
- return sourceFile;
- }
-
- private static <T extends StackTraceElementProxy<?>> Builder<T> builder(T originalElement) {
- return new Builder<>(originalElement);
- }
-
- public int getLineNumber() {
- return lineNumber;
- }
-
- private static class Builder<T extends StackTraceElementProxy<?>> {
-
- private final T originalElement;
- private RetracedClass classContext;
- private RetracedMethod methodContext;
- private String sourceFile;
- private int lineNumber = -1;
- private boolean isAmbiguous;
-
- private Builder(T originalElement) {
- this.originalElement = originalElement;
- }
-
- private Builder<T> setRetracedClassElement(RetracedClass retracedClass) {
- this.classContext = retracedClass;
- return this;
- }
-
- private Builder<T> setRetracedMethodElement(RetracedMethod methodElement) {
- this.methodContext = methodElement;
- return this;
- }
-
- private Builder<T> setSourceFile(String sourceFile) {
- this.sourceFile = sourceFile;
- return this;
- }
-
- private Builder<T> setLineNumber(int lineNumber) {
- this.lineNumber = lineNumber;
- return this;
- }
-
- private Builder<T> setAmbiguous(boolean ambiguous) {
- this.isAmbiguous = ambiguous;
- return this;
- }
-
- private RetraceStackTraceProxy<T> build() {
- RetracedClass retracedClass = classContext;
- if (methodContext != null) {
- retracedClass = methodContext.getHolderClass();
- }
- return new RetraceStackTraceProxy<>(
- originalElement,
- retracedClass,
- methodContext,
- sourceFile != null ? sourceFile : null,
- lineNumber,
- isAmbiguous);
- }
- }
- }
+ Stream<RetraceStackTraceProxyImpl<T>> retrace(T element);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/AmbiguousComparator.java b/src/main/java/com/android/tools/r8/retrace/internal/AmbiguousComparator.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/retrace/AmbiguousComparator.java
rename to src/main/java/com/android/tools/r8/retrace/internal/AmbiguousComparator.java
index 35266e7..d3c5a01 100644
--- a/src/main/java/com/android/tools/r8/retrace/AmbiguousComparator.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/AmbiguousComparator.java
@@ -2,7 +2,7 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import java.util.Comparator;
import java.util.function.BiFunction;
diff --git a/src/main/java/com/android/tools/r8/retrace/Definition.java b/src/main/java/com/android/tools/r8/retrace/internal/Definition.java
similarity index 88%
rename from src/main/java/com/android/tools/r8/retrace/Definition.java
rename to src/main/java/com/android/tools/r8/retrace/internal/Definition.java
index f955ac0..65a1736 100644
--- a/src/main/java/com/android/tools/r8/retrace/Definition.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/Definition.java
@@ -2,7 +2,7 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import com.android.tools.r8.references.ClassReference;
diff --git a/src/main/java/com/android/tools/r8/retrace/DirectClassNameMapperProguardMapProducer.java b/src/main/java/com/android/tools/r8/retrace/internal/DirectClassNameMapperProguardMapProducer.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/retrace/DirectClassNameMapperProguardMapProducer.java
rename to src/main/java/com/android/tools/r8/retrace/internal/DirectClassNameMapperProguardMapProducer.java
index 8efe05a..07bf237 100644
--- a/src/main/java/com/android/tools/r8/retrace/DirectClassNameMapperProguardMapProducer.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/DirectClassNameMapperProguardMapProducer.java
@@ -2,7 +2,7 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.retrace.RetraceCommand.ProguardMapProducer;
diff --git a/src/main/java/com/android/tools/r8/retrace/FieldDefinition.java b/src/main/java/com/android/tools/r8/retrace/internal/FieldDefinition.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/retrace/FieldDefinition.java
rename to src/main/java/com/android/tools/r8/retrace/internal/FieldDefinition.java
index 3dcf1c9..4a3b93c 100644
--- a/src/main/java/com/android/tools/r8/retrace/FieldDefinition.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/FieldDefinition.java
@@ -2,7 +2,7 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
diff --git a/src/main/java/com/android/tools/r8/retrace/MethodDefinition.java b/src/main/java/com/android/tools/r8/retrace/internal/MethodDefinition.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/retrace/MethodDefinition.java
rename to src/main/java/com/android/tools/r8/retrace/internal/MethodDefinition.java
index 8641f13..b1e23f5 100644
--- a/src/main/java/com/android/tools/r8/retrace/MethodDefinition.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/MethodDefinition.java
@@ -2,7 +2,7 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
diff --git a/src/main/java/com/android/tools/r8/retrace/PlainStackTraceVisitor.java b/src/main/java/com/android/tools/r8/retrace/internal/PlainStackTraceVisitor.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/retrace/PlainStackTraceVisitor.java
rename to src/main/java/com/android/tools/r8/retrace/internal/PlainStackTraceVisitor.java
index 1234b4d..0aac05f 100644
--- a/src/main/java/com/android/tools/r8/retrace/PlainStackTraceVisitor.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/PlainStackTraceVisitor.java
@@ -2,12 +2,12 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import static com.google.common.base.Predicates.not;
import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.retrace.StackTraceElementStringProxy.StackTraceElementStringProxyBuilder;
+import com.android.tools.r8.retrace.internal.StackTraceElementStringProxy.StackTraceElementStringProxyBuilder;
import com.android.tools.r8.utils.DescriptorUtils;
import java.util.List;
import java.util.function.Consumer;
@@ -19,7 +19,7 @@
private final List<String> stackTrace;
private final DiagnosticsHandler diagnosticsHandler;
- PlainStackTraceVisitor(List<String> stackTrace, DiagnosticsHandler diagnosticsHandler) {
+ public PlainStackTraceVisitor(List<String> stackTrace, DiagnosticsHandler diagnosticsHandler) {
this.stackTrace = stackTrace;
this.diagnosticsHandler = diagnosticsHandler;
}
@@ -209,7 +209,7 @@
private StackTraceElementStringProxy parseLine(int lineNumber, String line) {
if (line == null) {
diagnosticsHandler.error(RetraceInvalidStackTraceLineDiagnostics.createNull(lineNumber));
- throw new Retrace.RetraceAbortException();
+ throw new RetraceAbortException();
}
// Most lines are 'at lines' so attempt to parse it first.
StackTraceElementStringProxy parsedLine = AtLine.tryParse(line);
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceAbortException.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceAbortException.java
new file mode 100644
index 0000000..60eee2f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceAbortException.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+public class RetraceAbortException extends RuntimeException {}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
new file mode 100644
index 0000000..45b7fdd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -0,0 +1,346 @@
+// Copyright (c) 2019, 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.retrace.internal;
+
+import static com.android.tools.r8.naming.MemberNaming.NoSignature.NO_SIGNATURE;
+import static com.android.tools.r8.retrace.internal.RetraceUtils.synthesizeFileName;
+
+import com.android.tools.r8.naming.ClassNamingForNameMapper;
+import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
+import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
+import com.android.tools.r8.naming.MemberNaming;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.RetraceClassResult;
+import com.android.tools.r8.retrace.RetraceFrameResult;
+import com.android.tools.r8.utils.Pair;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+public class RetraceClassResultImpl implements RetraceClassResult {
+
+ private final ClassReference obfuscatedReference;
+ private final ClassNamingForNameMapper mapper;
+ private final RetracerImpl retracer;
+
+ private RetraceClassResultImpl(
+ ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetracerImpl retracer) {
+ this.obfuscatedReference = obfuscatedReference;
+ this.mapper = mapper;
+ this.retracer = retracer;
+ }
+
+ static RetraceClassResultImpl create(
+ ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetracerImpl retracer) {
+ return new RetraceClassResultImpl(obfuscatedReference, mapper, retracer);
+ }
+
+ @Override
+ public RetraceFieldResultImpl lookupField(String fieldName) {
+ return lookupField(FieldDefinition.create(obfuscatedReference, fieldName));
+ }
+
+ @Override
+ public RetraceFieldResultImpl lookupField(String fieldName, TypeReference fieldType) {
+ return lookupField(
+ FieldDefinition.create(Reference.field(obfuscatedReference, fieldName, fieldType)));
+ }
+
+ @Override
+ public RetraceMethodResultImpl lookupMethod(String methodName) {
+ return lookupMethod(MethodDefinition.create(obfuscatedReference, methodName));
+ }
+
+ @Override
+ public RetraceMethodResultImpl lookupMethod(
+ String methodName, List<TypeReference> formalTypes, TypeReference returnType) {
+ return lookupMethod(
+ MethodDefinition.create(
+ Reference.method(obfuscatedReference, methodName, formalTypes, returnType)));
+ }
+
+ private RetraceFieldResultImpl lookupField(FieldDefinition fieldDefinition) {
+ return lookup(
+ fieldDefinition,
+ (mapper, name) -> {
+ List<MemberNaming> memberNamings = mapper.mappedFieldNamingsByName.get(name);
+ if (memberNamings == null || memberNamings.isEmpty()) {
+ return null;
+ }
+ return memberNamings;
+ },
+ RetraceFieldResultImpl::new);
+ }
+
+ private RetraceMethodResultImpl lookupMethod(MethodDefinition methodDefinition) {
+ return lookup(
+ methodDefinition,
+ (mapper, name) -> {
+ MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(name);
+ if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
+ return null;
+ }
+ return mappedRanges.getMappedRanges();
+ },
+ RetraceMethodResultImpl::new);
+ }
+
+ private <T, R, D extends Definition> R lookup(
+ D definition,
+ BiFunction<ClassNamingForNameMapper, String, T> lookupFunction,
+ ResultConstructor<T, R, D> constructor) {
+ List<Pair<ElementImpl, T>> mappings = new ArrayList<>();
+ internalStream()
+ .forEach(
+ element -> {
+ if (mapper != null) {
+ assert element.mapper != null;
+ T mappedElements = lookupFunction.apply(element.mapper, definition.getName());
+ if (mappedElements != null) {
+ mappings.add(new Pair<>(element, mappedElements));
+ return;
+ }
+ }
+ mappings.add(new Pair<>(element, null));
+ });
+ return constructor.create(this, mappings, definition, retracer);
+ }
+
+ @Override
+ public RetraceFrameResultImpl lookupFrame(String methodName) {
+ return lookupFrame(MethodDefinition.create(obfuscatedReference, methodName), -1);
+ }
+
+ @Override
+ public RetraceFrameResultImpl lookupFrame(String methodName, int position) {
+ return lookupFrame(MethodDefinition.create(obfuscatedReference, methodName), position);
+ }
+
+ @Override
+ public RetraceFrameResultImpl lookupFrame(
+ String methodName, int position, List<TypeReference> formalTypes, TypeReference returnType) {
+ return lookupFrame(
+ MethodDefinition.create(
+ Reference.method(obfuscatedReference, methodName, formalTypes, returnType)),
+ position);
+ }
+
+ private RetraceFrameResultImpl lookupFrame(MethodDefinition definition, int position) {
+ List<Pair<ElementImpl, List<MappedRange>>> mappings = new ArrayList<>();
+ internalStream()
+ .forEach(
+ element ->
+ mappings.add(
+ new Pair<>(element, getMappedRangesForFrame(element, definition, position))));
+ return new RetraceFrameResultImpl(this, mappings, definition, position, retracer);
+ }
+
+ private List<MappedRange> getMappedRangesForFrame(
+ ElementImpl element, MethodDefinition definition, int position) {
+ if (mapper == null) {
+ return null;
+ }
+ assert element.mapper != null;
+ MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(definition.getName());
+ if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
+ return null;
+ }
+ if (position <= 0) {
+ return mappedRanges.getMappedRanges();
+ }
+ List<MappedRange> mappedRangesForPosition = mappedRanges.allRangesForLine(position, false);
+ return mappedRangesForPosition.isEmpty()
+ ? mappedRanges.getMappedRanges()
+ : mappedRangesForPosition;
+ }
+
+ boolean hasRetraceResult() {
+ return mapper != null;
+ }
+
+ @Override
+ public Stream<Element> stream() {
+ return Stream.of(createElement());
+ }
+
+ private Stream<ElementImpl> internalStream() {
+ return Stream.of(createElement());
+ }
+
+ private ElementImpl createElement() {
+ return new ElementImpl(
+ this,
+ RetracedClassImpl.create(
+ mapper == null
+ ? obfuscatedReference
+ : Reference.classFromTypeName(mapper.originalName)),
+ mapper);
+ }
+
+ @Override
+ public RetraceClassResultImpl forEach(Consumer<Element> resultConsumer) {
+ stream().forEach(resultConsumer);
+ return this;
+ }
+
+ private interface ResultConstructor<T, R, D> {
+ R create(
+ RetraceClassResultImpl classResult,
+ List<Pair<ElementImpl, T>> mappings,
+ D definition,
+ RetracerImpl retracer);
+ }
+
+ @Override
+ public boolean isAmbiguous() {
+ // Currently we have no way of producing ambiguous class results.
+ return false;
+ }
+
+ public static class ElementImpl implements Element {
+
+ private final RetraceClassResultImpl classResult;
+ private final RetracedClassImpl classReference;
+ private final ClassNamingForNameMapper mapper;
+
+ public ElementImpl(
+ RetraceClassResultImpl classResult,
+ RetracedClassImpl classReference,
+ ClassNamingForNameMapper mapper) {
+ this.classResult = classResult;
+ this.classReference = classReference;
+ this.mapper = mapper;
+ }
+
+ @Override
+ public RetracedClassImpl getRetracedClass() {
+ return classReference;
+ }
+
+ @Override
+ public RetraceClassResultImpl getRetraceClassResult() {
+ return classResult;
+ }
+
+ @Override
+ public RetraceSourceFileResultImpl retraceSourceFile(String sourceFile) {
+ if (mapper != null && mapper.getAdditionalMappings().size() > 0) {
+ List<MappingInformation> mappingInformations =
+ mapper.getAdditionalMappings().get(NO_SIGNATURE);
+ if (mappingInformations != null) {
+ for (MappingInformation mappingInformation : mappingInformations) {
+ if (mappingInformation.isFileNameInformation()) {
+ return new RetraceSourceFileResultImpl(
+ mappingInformation.asFileNameInformation().getFileName(), false);
+ }
+ }
+ }
+ }
+ return new RetraceSourceFileResultImpl(
+ synthesizeFileName(
+ classReference.getTypeName(),
+ classResult.obfuscatedReference.getTypeName(),
+ sourceFile,
+ mapper != null),
+ true);
+ }
+
+ @Override
+ public RetraceFieldResultImpl lookupField(String fieldName) {
+ return lookupField(FieldDefinition.create(classReference.getClassReference(), fieldName));
+ }
+
+ private RetraceFieldResultImpl lookupField(FieldDefinition fieldDefinition) {
+ return lookup(
+ fieldDefinition,
+ (mapper, name) -> {
+ List<MemberNaming> memberNamings = mapper.mappedFieldNamingsByName.get(name);
+ if (memberNamings == null || memberNamings.isEmpty()) {
+ return null;
+ }
+ return memberNamings;
+ },
+ RetraceFieldResultImpl::new);
+ }
+
+ @Override
+ public RetraceMethodResultImpl lookupMethod(String methodName) {
+ return lookupMethod(MethodDefinition.create(classReference.getClassReference(), methodName));
+ }
+
+ private RetraceMethodResultImpl lookupMethod(MethodDefinition methodDefinition) {
+ return lookup(
+ methodDefinition,
+ (mapper, name) -> {
+ MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(name);
+ if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
+ return null;
+ }
+ return mappedRanges.getMappedRanges();
+ },
+ RetraceMethodResultImpl::new);
+ }
+
+ private <T, R, D extends Definition> R lookup(
+ D definition,
+ BiFunction<ClassNamingForNameMapper, String, T> lookupFunction,
+ ResultConstructor<T, R, D> constructor) {
+ List<Pair<ElementImpl, T>> mappings = ImmutableList.of();
+ if (mapper != null) {
+ T result = lookupFunction.apply(mapper, definition.getName());
+ if (result != null) {
+ mappings = ImmutableList.of(new Pair<>(this, result));
+ }
+ }
+ if (mappings.isEmpty()) {
+ mappings = ImmutableList.of(new Pair<>(this, null));
+ }
+ return constructor.create(classResult, mappings, definition, classResult.retracer);
+ }
+
+ @Override
+ public RetraceFrameResultImpl lookupFrame(String methodName) {
+ return lookupFrame(methodName, -1);
+ }
+
+ @Override
+ public RetraceFrameResultImpl lookupFrame(String methodName, int position) {
+ return lookupFrame(
+ MethodDefinition.create(classReference.getClassReference(), methodName), position);
+ }
+
+ @Override
+ public RetraceFrameResult lookupFrame(
+ String methodName,
+ int position,
+ List<TypeReference> formalTypes,
+ TypeReference returnType) {
+ return lookupFrame(
+ MethodDefinition.create(
+ Reference.method(
+ classReference.getClassReference(), methodName, formalTypes, returnType)),
+ position);
+ }
+
+ private RetraceFrameResultImpl lookupFrame(MethodDefinition definition, int position) {
+ MethodDefinition methodDefinition =
+ MethodDefinition.create(classReference.getClassReference(), definition.getName());
+ return new RetraceFrameResultImpl(
+ classResult,
+ ImmutableList.of(
+ new Pair<>(
+ this, classResult.getMappedRangesForFrame(this, methodDefinition, position))),
+ methodDefinition,
+ position,
+ classResult.retracer);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceCommandLineResult.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceCommandLineResult.java
similarity index 67%
rename from src/main/java/com/android/tools/r8/retrace/RetraceCommandLineResult.java
rename to src/main/java/com/android/tools/r8/retrace/internal/RetraceCommandLineResult.java
index 00f1857..8686ede 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceCommandLineResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceCommandLineResult.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.retrace;
+package com.android.tools.r8.retrace.internal;
import java.util.List;
@@ -10,7 +10,7 @@
private final List<String> nodes;
- RetraceCommandLineResult(List<String> nodes) {
+ public RetraceCommandLineResult(List<String> nodes) {
this.nodes = nodes;
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
new file mode 100644
index 0000000..066b979
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
@@ -0,0 +1,135 @@
+// Copyright (c) 2019, 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.retrace.internal;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.naming.MemberNaming;
+import com.android.tools.r8.naming.MemberNaming.FieldSignature;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.RetraceFieldResult;
+import com.android.tools.r8.retrace.Retracer;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.Pair;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+@Keep
+public class RetraceFieldResultImpl implements RetraceFieldResult {
+
+ private final RetraceClassResultImpl classResult;
+ private final List<Pair<RetraceClassResultImpl.ElementImpl, List<MemberNaming>>> memberNamings;
+ private final FieldDefinition fieldDefinition;
+ private final Retracer retracer;
+
+ RetraceFieldResultImpl(
+ RetraceClassResultImpl classResult,
+ List<Pair<RetraceClassResultImpl.ElementImpl, List<MemberNaming>>> memberNamings,
+ FieldDefinition fieldDefinition,
+ Retracer retracer) {
+ this.classResult = classResult;
+ this.memberNamings = memberNamings;
+ this.fieldDefinition = fieldDefinition;
+ this.retracer = retracer;
+ assert classResult != null;
+ assert !memberNamings.isEmpty();
+ }
+
+ @Override
+ public Stream<Element> stream() {
+ return memberNamings.stream()
+ .flatMap(
+ mappedNamePair -> {
+ RetraceClassResultImpl.ElementImpl classElement = mappedNamePair.getFirst();
+ List<MemberNaming> memberNamings = mappedNamePair.getSecond();
+ if (memberNamings == null) {
+ return Stream.of(
+ new ElementImpl(
+ this,
+ classElement,
+ RetracedFieldImpl.create(
+ fieldDefinition.substituteHolder(
+ classElement.getRetracedClass().getClassReference()))));
+ }
+ return memberNamings.stream()
+ .map(
+ memberNaming -> {
+ FieldSignature fieldSignature =
+ memberNaming.getOriginalSignature().asFieldSignature();
+ RetracedClassImpl holder =
+ fieldSignature.isQualified()
+ ? RetracedClassImpl.create(
+ Reference.classFromDescriptor(
+ DescriptorUtils.javaTypeToDescriptor(
+ fieldSignature.toHolderFromQualified())))
+ : classElement.getRetracedClass();
+ return new ElementImpl(
+ this,
+ classElement,
+ RetracedFieldImpl.create(
+ Reference.field(
+ holder.getClassReference(),
+ fieldSignature.isQualified()
+ ? fieldSignature.toUnqualifiedName()
+ : fieldSignature.name,
+ Reference.typeFromTypeName(fieldSignature.type))));
+ });
+ });
+ }
+
+ @Override
+ public RetraceFieldResultImpl forEach(Consumer<Element> resultConsumer) {
+ stream().forEach(resultConsumer);
+ return this;
+ }
+
+ @Override
+ public boolean isAmbiguous() {
+ if (memberNamings.size() > 1) {
+ return true;
+ }
+ List<MemberNaming> mappings = memberNamings.get(0).getSecond();
+ if (mappings == null) {
+ return false;
+ }
+ return mappings.size() > 1;
+ }
+
+ public static class ElementImpl implements RetraceFieldResult.Element {
+
+ private final RetracedFieldImpl fieldReference;
+ private final RetraceFieldResultImpl retraceFieldResult;
+ private final RetraceClassResultImpl.ElementImpl classElement;
+
+ private ElementImpl(
+ RetraceFieldResultImpl retraceFieldResult,
+ RetraceClassResultImpl.ElementImpl classElement,
+ RetracedFieldImpl fieldReference) {
+ this.classElement = classElement;
+ this.fieldReference = fieldReference;
+ this.retraceFieldResult = retraceFieldResult;
+ }
+
+ @Override
+ public boolean isUnknown() {
+ return fieldReference.isUnknown();
+ }
+
+ @Override
+ public RetracedFieldImpl getField() {
+ return fieldReference;
+ }
+
+ @Override
+ public RetraceFieldResultImpl getRetraceFieldResult() {
+ return retraceFieldResult;
+ }
+
+ @Override
+ public RetraceClassResultImpl.ElementImpl getClassElement() {
+ return classElement;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
new file mode 100644
index 0000000..24c5a8e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
@@ -0,0 +1,203 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+import static com.android.tools.r8.retrace.internal.RetraceUtils.methodReferenceFromMappedRange;
+
+import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
+import com.android.tools.r8.naming.Range;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.retrace.RetraceFrameResult;
+import com.android.tools.r8.retrace.RetraceSourceFileResult;
+import com.android.tools.r8.retrace.RetracedClassMember;
+import com.android.tools.r8.retrace.RetracedMethod;
+import com.android.tools.r8.utils.Pair;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+public class RetraceFrameResultImpl implements RetraceFrameResult {
+
+ private final RetraceClassResultImpl classResult;
+ private final MethodDefinition methodDefinition;
+ private final int obfuscatedPosition;
+ private final List<Pair<RetraceClassResultImpl.ElementImpl, List<MappedRange>>> mappedRanges;
+ private final RetracerImpl retracer;
+
+ public RetraceFrameResultImpl(
+ RetraceClassResultImpl classResult,
+ List<Pair<RetraceClassResultImpl.ElementImpl, List<MappedRange>>> mappedRanges,
+ MethodDefinition methodDefinition,
+ int obfuscatedPosition,
+ RetracerImpl retracer) {
+ this.classResult = classResult;
+ this.methodDefinition = methodDefinition;
+ this.obfuscatedPosition = obfuscatedPosition;
+ this.mappedRanges = mappedRanges;
+ this.retracer = retracer;
+ }
+
+ @Override
+ public boolean isAmbiguous() {
+ if (mappedRanges.size() > 1) {
+ return true;
+ }
+ List<MappedRange> methodRanges = mappedRanges.get(0).getSecond();
+ if (methodRanges == null || methodRanges.isEmpty()) {
+ return false;
+ }
+ MappedRange lastRange = methodRanges.get(0);
+ for (MappedRange mappedRange : methodRanges) {
+ if (mappedRange != lastRange
+ && (mappedRange.minifiedRange == null
+ || !mappedRange.minifiedRange.equals(lastRange.minifiedRange))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Stream<Element> stream() {
+ return mappedRanges.stream()
+ .flatMap(
+ mappedRangePair -> {
+ RetraceClassResultImpl.ElementImpl classElement = mappedRangePair.getFirst();
+ List<MappedRange> mappedRanges = mappedRangePair.getSecond();
+ if (mappedRanges == null || mappedRanges.isEmpty()) {
+ return Stream.of(
+ new ElementImpl(
+ this,
+ classElement,
+ RetracedMethodImpl.create(
+ methodDefinition.substituteHolder(
+ classElement.getRetracedClass().getClassReference())),
+ ImmutableList.of(),
+ obfuscatedPosition));
+ }
+ // Iterate over mapped ranges that may have different positions than specified.
+ List<ElementImpl> ambiguousFrames = new ArrayList<>();
+ Range minifiedRange = mappedRanges.get(0).minifiedRange;
+ List<MappedRange> mappedRangesForElement = Lists.newArrayList(mappedRanges.get(0));
+ for (int i = 1; i < mappedRanges.size(); i++) {
+ MappedRange mappedRange = mappedRanges.get(i);
+ if (minifiedRange == null || !minifiedRange.equals(mappedRange.minifiedRange)) {
+ // This is a new frame
+ ambiguousFrames.add(
+ elementFromMappedRanges(mappedRangesForElement, classElement));
+ mappedRangesForElement = new ArrayList<>();
+ }
+ mappedRangesForElement.add(mappedRange);
+ }
+ ambiguousFrames.add(elementFromMappedRanges(mappedRangesForElement, classElement));
+ return ambiguousFrames.stream();
+ });
+ }
+
+ private ElementImpl elementFromMappedRanges(
+ List<MappedRange> mappedRangesForElement, RetraceClassResultImpl.ElementImpl classElement) {
+ MappedRange topFrame = mappedRangesForElement.get(0);
+ MethodReference methodReference =
+ methodReferenceFromMappedRange(
+ topFrame, classElement.getRetracedClass().getClassReference());
+ return new ElementImpl(
+ this,
+ classElement,
+ getRetracedMethod(methodReference, topFrame, obfuscatedPosition),
+ mappedRangesForElement,
+ obfuscatedPosition);
+ }
+
+ @Override
+ public RetraceFrameResultImpl forEach(Consumer<Element> resultConsumer) {
+ stream().forEach(resultConsumer);
+ return this;
+ }
+
+ private RetracedMethodImpl getRetracedMethod(
+ MethodReference methodReference, MappedRange mappedRange, int obfuscatedPosition) {
+ if (obfuscatedPosition == -1
+ || mappedRange.minifiedRange == null
+ || !mappedRange.minifiedRange.contains(obfuscatedPosition)) {
+ return RetracedMethodImpl.create(methodReference);
+ }
+ return RetracedMethodImpl.create(
+ methodReference, mappedRange.getOriginalLineNumber(obfuscatedPosition));
+ }
+
+ public static class ElementImpl implements RetraceFrameResult.Element {
+
+ private final RetracedMethodImpl methodReference;
+ private final RetraceFrameResultImpl retraceFrameResult;
+ private final RetraceClassResultImpl.ElementImpl classElement;
+ private final List<MappedRange> mappedRanges;
+ private final int obfuscatedPosition;
+
+ public ElementImpl(
+ RetraceFrameResultImpl retraceFrameResult,
+ RetraceClassResultImpl.ElementImpl classElement,
+ RetracedMethodImpl methodReference,
+ List<MappedRange> mappedRanges,
+ int obfuscatedPosition) {
+ this.methodReference = methodReference;
+ this.retraceFrameResult = retraceFrameResult;
+ this.classElement = classElement;
+ this.mappedRanges = mappedRanges;
+ this.obfuscatedPosition = obfuscatedPosition;
+ }
+
+ @Override
+ public boolean isUnknown() {
+ return methodReference.isUnknown();
+ }
+
+ @Override
+ public RetracedMethodImpl getTopFrame() {
+ return methodReference;
+ }
+
+ @Override
+ public RetraceClassResultImpl.ElementImpl getClassElement() {
+ return classElement;
+ }
+
+ @Override
+ public void visitFrames(BiConsumer<RetracedMethod, Integer> consumer) {
+ int counter = 0;
+ consumer.accept(getTopFrame(), counter++);
+ for (RetracedMethodImpl outerFrame : getOuterFrames()) {
+ consumer.accept(outerFrame, counter++);
+ }
+ }
+
+ @Override
+ public RetraceSourceFileResult retraceSourceFile(RetracedClassMember frame, String sourceFile) {
+ return RetraceUtils.getSourceFile(
+ classElement, frame.getHolderClass(), sourceFile, retraceFrameResult.retracer);
+ }
+
+ @Override
+ public List<RetracedMethodImpl> getOuterFrames() {
+ if (mappedRanges == null) {
+ return Collections.emptyList();
+ }
+ List<RetracedMethodImpl> outerFrames = new ArrayList<>();
+ for (int i = 1; i < mappedRanges.size(); i++) {
+ MappedRange mappedRange = mappedRanges.get(i);
+ MethodReference methodReference =
+ methodReferenceFromMappedRange(
+ mappedRange, classElement.getRetracedClass().getClassReference());
+ outerFrames.add(
+ retraceFrameResult.getRetracedMethod(methodReference, mappedRange, obfuscatedPosition));
+ }
+ return outerFrames;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceInvalidStackTraceLineDiagnostics.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceInvalidStackTraceLineDiagnostics.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/retrace/RetraceInvalidStackTraceLineDiagnostics.java
rename to src/main/java/com/android/tools/r8/retrace/internal/RetraceInvalidStackTraceLineDiagnostics.java
index 959976a..547534f 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceInvalidStackTraceLineDiagnostics.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceInvalidStackTraceLineDiagnostics.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.retrace;
+package com.android.tools.r8.retrace.internal;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.Keep;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
new file mode 100644
index 0000000..93fa544
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
@@ -0,0 +1,174 @@
+// Copyright (c) 2019, 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.retrace.internal;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
+import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.retrace.RetraceMethodResult;
+import com.android.tools.r8.utils.Pair;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+@Keep
+public class RetraceMethodResultImpl implements RetraceMethodResult {
+
+ private final MethodDefinition methodDefinition;
+ private final RetraceClassResultImpl classResult;
+ private final List<Pair<RetraceClassResultImpl.ElementImpl, List<MappedRange>>> mappedRanges;
+ private final RetracerImpl retracer;
+
+ RetraceMethodResultImpl(
+ RetraceClassResultImpl classResult,
+ List<Pair<RetraceClassResultImpl.ElementImpl, List<MappedRange>>> mappedRanges,
+ MethodDefinition methodDefinition,
+ RetracerImpl retracer) {
+ this.classResult = classResult;
+ this.mappedRanges = mappedRanges;
+ this.methodDefinition = methodDefinition;
+ this.retracer = retracer;
+ assert classResult != null;
+ assert !mappedRanges.isEmpty();
+ }
+
+ @Override
+ public boolean isAmbiguous() {
+ if (mappedRanges.size() > 1) {
+ return true;
+ }
+ List<MappedRange> methodRanges = mappedRanges.get(0).getSecond();
+ if (methodRanges == null || methodRanges.isEmpty()) {
+ return false;
+ }
+ MappedRange lastRange = methodRanges.get(0);
+ for (MappedRange mappedRange : methodRanges) {
+ if (mappedRange != lastRange
+ && (mappedRange.minifiedRange == null
+ || !mappedRange.minifiedRange.equals(lastRange.minifiedRange))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public RetraceFrameResultImpl narrowByPosition(int position) {
+ List<Pair<RetraceClassResultImpl.ElementImpl, List<MappedRange>>> narrowedRanges =
+ new ArrayList<>();
+ List<Pair<RetraceClassResultImpl.ElementImpl, List<MappedRange>>> noMappingRanges =
+ new ArrayList<>();
+ for (Pair<RetraceClassResultImpl.ElementImpl, List<MappedRange>> mappedRange : mappedRanges) {
+ if (mappedRange.getSecond() == null) {
+ noMappingRanges.add(new Pair<>(mappedRange.getFirst(), null));
+ continue;
+ }
+ List<MappedRange> ranges =
+ new MappedRangesOfName(mappedRange.getSecond()).allRangesForLine(position, false);
+ boolean hasAddedRanges = false;
+ if (!ranges.isEmpty()) {
+ narrowedRanges.add(new Pair<>(mappedRange.getFirst(), ranges));
+ hasAddedRanges = true;
+ } else {
+ narrowedRanges = new ArrayList<>();
+ for (MappedRange mapped : mappedRange.getSecond()) {
+ if (mapped.minifiedRange == null) {
+ narrowedRanges.add(new Pair<>(mappedRange.getFirst(), ImmutableList.of(mapped)));
+ hasAddedRanges = true;
+ }
+ }
+ }
+ if (!hasAddedRanges) {
+ narrowedRanges.add(new Pair<>(mappedRange.getFirst(), null));
+ }
+ }
+ return new RetraceFrameResultImpl(
+ classResult,
+ narrowedRanges.isEmpty() ? noMappingRanges : narrowedRanges,
+ methodDefinition,
+ position,
+ retracer);
+ }
+
+ @Override
+ public Stream<Element> stream() {
+ return mappedRanges.stream()
+ .flatMap(
+ mappedRangePair -> {
+ RetraceClassResultImpl.ElementImpl classElement = mappedRangePair.getFirst();
+ List<MappedRange> mappedRanges = mappedRangePair.getSecond();
+ if (mappedRanges == null || mappedRanges.isEmpty()) {
+ return Stream.of(
+ new ElementImpl(
+ this,
+ classElement,
+ RetracedMethodImpl.create(
+ methodDefinition.substituteHolder(
+ classElement.getRetracedClass().getClassReference()))));
+ }
+ return mappedRanges.stream()
+ .map(
+ mappedRange -> {
+ MethodReference methodReference =
+ RetraceUtils.methodReferenceFromMappedRange(
+ mappedRange, classElement.getRetracedClass().getClassReference());
+ return new ElementImpl(
+ this, classElement, RetracedMethodImpl.create(methodReference));
+ });
+ });
+ }
+
+ @Override
+ public RetraceMethodResultImpl forEach(Consumer<Element> resultConsumer) {
+ stream().forEach(resultConsumer);
+ return this;
+ }
+
+ public static class ElementImpl implements RetraceMethodResult.Element {
+
+ private final RetracedMethodImpl methodReference;
+ private final RetraceMethodResultImpl retraceMethodResult;
+ private final RetraceClassResultImpl.ElementImpl classElement;
+
+ private ElementImpl(
+ RetraceMethodResultImpl retraceMethodResult,
+ RetraceClassResultImpl.ElementImpl classElement,
+ RetracedMethodImpl methodReference) {
+ this.classElement = classElement;
+ this.retraceMethodResult = retraceMethodResult;
+ this.methodReference = methodReference;
+ }
+
+ @Override
+ public boolean isUnknown() {
+ return methodReference.isUnknown();
+ }
+
+ @Override
+ public com.android.tools.r8.retrace.RetracedMethod getRetracedMethod() {
+ return null;
+ }
+
+ @Override
+ public RetraceMethodResultImpl getRetraceMethodResult() {
+ return retraceMethodResult;
+ }
+
+ @Override
+ public RetraceClassResultImpl.ElementImpl getClassElement() {
+ return classElement;
+ }
+
+ @Override
+ public com.android.tools.r8.retrace.RetraceSourceFileResult retraceSourceFile(
+ String sourceFile) {
+ return RetraceUtils.getSourceFile(
+ classElement, methodReference.getHolderClass(), sourceFile, retraceMethodResult.retracer);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceRegularExpression.java
similarity index 91%
rename from src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
rename to src/main/java/com/android/tools/r8/retrace/internal/RetraceRegularExpression.java
index 910db1a..6ba4d1a 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceRegularExpression.java
@@ -2,18 +2,25 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
-import static com.android.tools.r8.retrace.RetraceUtils.methodDescriptionFromRetraceMethod;
+import static com.android.tools.r8.retrace.internal.RetraceUtils.methodDescriptionFromRetraceMethod;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.retrace.RetraceClassResult.Element;
-import com.android.tools.r8.retrace.RetraceRegularExpression.ClassNameGroup.ClassNameGroupHandler;
+import com.android.tools.r8.retrace.RetraceClassResult;
+import com.android.tools.r8.retrace.RetraceFieldResult;
+import com.android.tools.r8.retrace.RetraceFrameResult;
+import com.android.tools.r8.retrace.RetraceFrameResult.Element;
+import com.android.tools.r8.retrace.RetraceSourceFileResult;
+import com.android.tools.r8.retrace.RetracedClass;
+import com.android.tools.r8.retrace.RetracedField;
import com.android.tools.r8.retrace.RetracedField.KnownRetracedField;
+import com.android.tools.r8.retrace.RetracedMethod;
+import com.android.tools.r8.retrace.internal.RetraceRegularExpression.ClassNameGroup.ClassNameGroupHandler;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -30,7 +37,7 @@
public class RetraceRegularExpression {
- private final RetraceApi retracer;
+ private final RetracerImpl retracer;
private final List<String> stackTrace;
private final DiagnosticsHandler diagnosticsHandler;
private final String regularExpression;
@@ -52,8 +59,8 @@
private static final String CAPTURE_GROUP_PREFIX = "captureGroup";
private static final int FIRST_CAPTURE_GROUP_INDEX = 0;
- RetraceRegularExpression(
- RetraceApi retracer,
+ public RetraceRegularExpression(
+ RetracerImpl retracer,
List<String> stackTrace,
DiagnosticsHandler diagnosticsHandler,
String regularExpression,
@@ -134,7 +141,7 @@
case CLASS:
return line.getClassContext().getRetracedClass().getTypeName();
case METHOD:
- return line.getMethodContext().getMember().getMethodName();
+ return line.getMethodContext().getTopFrame().getMethodName();
case SOURCE:
return line.getSource();
case LINE:
@@ -241,8 +248,8 @@
}
static class RetraceStringContext {
- private final Element classContext;
- private final RetraceClassMemberElement<? extends RetracedMethod> methodContext;
+ private final RetraceClassResult.Element classContext;
+ private final RetraceFrameResult.Element methodContext;
private final RetracedClass qualifiedClassContext;
private final RetracedMethod qualifiedMethodContext;
private final String methodName;
@@ -252,8 +259,8 @@
private final boolean isAmbiguous;
private RetraceStringContext(
- Element classContext,
- RetraceClassMemberElement<? extends RetracedMethod> methodContext,
+ RetraceClassResult.Element classContext,
+ RetraceFrameResult.Element methodContext,
RetracedClass qualifiedClassContext,
RetracedMethod qualifiedMethodContext,
String methodName,
@@ -278,7 +285,7 @@
}
private RetraceStringContext withClassContext(
- Element classContext, RetracedClass qualifiedContext) {
+ RetraceClassResult.Element classContext, RetracedClass qualifiedContext) {
return new RetraceStringContext(
classContext,
methodContext,
@@ -304,8 +311,7 @@
isAmbiguous);
}
- private RetraceStringContext withMethodContext(
- RetraceClassMemberElement<? extends RetracedMethod> methodContext, boolean isAmbiguous) {
+ private RetraceStringContext withMethodContext(Element methodContext, boolean isAmbiguous) {
return new RetraceStringContext(
classContext,
methodContext,
@@ -403,11 +409,11 @@
this.context = context;
}
- private Element getClassContext() {
+ private RetraceClassResult.Element getClassContext() {
return context.classContext;
}
- private RetraceClassMemberElement<? extends RetracedMethod> getMethodContext() {
+ private RetraceFrameResult.Element getMethodContext() {
return context.methodContext;
}
@@ -448,10 +454,10 @@
private interface RegularExpressionGroupHandler {
List<RetraceString> handleMatch(
- String original, List<RetraceString> strings, Matcher matcher, RetraceApi retracer);
+ String original, List<RetraceString> strings, Matcher matcher, RetracerImpl retracer);
default RetraceStringContext buildInitial(
- RetraceStringContext context, Matcher matcher, RetraceApi retracer) {
+ RetraceStringContext context, Matcher matcher, RetracerImpl retracer) {
return context;
}
@@ -518,7 +524,7 @@
static class ClassNameGroupHandler implements RegularExpressionGroupHandler {
- private RetraceClassResult retraceClassResult = null;
+ private RetraceClassResultImpl retraceClassResult = null;
private final ClassNameGroup classNameGroup;
private final String captureGroup;
private RegularExpressionGroupHandler qualifiedHandler;
@@ -530,15 +536,15 @@
@Override
public List<RetraceString> handleMatch(
- String original, List<RetraceString> strings, Matcher matcher, RetraceApi retracer) {
+ String original, List<RetraceString> strings, Matcher matcher, RetracerImpl retracer) {
final int startOfGroup = matcher.start(captureGroup);
if (startOfGroup == NO_MATCH) {
return strings;
}
String typeName = matcher.group(captureGroup);
- RetraceClassResult retraceResult =
+ RetraceClassResultImpl retraceResult =
retraceClassResult == null
- ? retracer.retrace(classNameGroup.classFromMatch(typeName))
+ ? retracer.retraceClass(classNameGroup.classFromMatch(typeName))
: retraceClassResult;
assert !retraceResult.isAmbiguous();
List<RetraceString> retraceStrings = new ArrayList<>(strings.size());
@@ -579,14 +585,14 @@
@Override
public RetraceStringContext buildInitial(
- RetraceStringContext context, Matcher matcher, RetraceApi retracer) {
+ RetraceStringContext context, Matcher matcher, RetracerImpl retracer) {
// Reset the local class context since this the same handler is used for multiple lines.
retraceClassResult = null;
if (matcher.start(captureGroup) == NO_MATCH || context.classContext != null) {
return context;
}
String typeName = matcher.group(captureGroup);
- retraceClassResult = retracer.retrace(classNameGroup.classFromMatch(typeName));
+ retraceClassResult = retracer.retraceClass(classNameGroup.classFromMatch(typeName));
assert !retraceClassResult.isAmbiguous();
Box<RetraceStringContext> box = new Box<>();
retraceClassResult.forEach(
@@ -673,7 +679,7 @@
@Override
public List<RetraceString> handleMatch(
- String original, List<RetraceString> strings, Matcher matcher, RetraceApi retracer) {
+ String original, List<RetraceString> strings, Matcher matcher, RetracerImpl retracer) {
final int startOfGroup = matcher.start(captureGroup);
if (startOfGroup == NO_MATCH) {
if (classNameGroupHandler != null) {
@@ -715,7 +721,7 @@
@Override
public RetraceStringContext buildInitial(
- RetraceStringContext context, Matcher matcher, RetraceApi retracer) {
+ RetraceStringContext context, Matcher matcher, RetracerImpl retracer) {
final int startOfGroup = matcher.start(captureGroup);
if (startOfGroup == NO_MATCH || context.methodName != null) {
return context;
@@ -728,25 +734,21 @@
private static void retraceMethodForString(
RetraceString retraceString,
String methodName,
- BiConsumer<RetraceClassMemberElement<? extends RetracedMethod>, RetraceStringContext>
- process) {
+ BiConsumer<Element, RetraceStringContext> process) {
if (retraceString.context.classContext == null) {
return;
}
- RetraceMethodResult retraceMethodResult =
- retraceString.getClassContext().lookupMethod(methodName);
- Result<? extends RetraceClassMemberElement<RetracedMethod>, ?> retraceResult;
- if (retraceString.context.minifiedLineNumber > NO_MATCH) {
- retraceResult =
- retraceMethodResult.narrowByPosition(retraceString.context.minifiedLineNumber);
- } else {
- retraceResult = retraceMethodResult;
- }
- retraceResult.forEach(
- element ->
- process.accept(
- element,
- retraceString.context.withMethodContext(element, retraceResult.isAmbiguous())));
+ RetraceClassResult.Element classContext = retraceString.getClassContext();
+ RetraceFrameResult retraceFrameResult =
+ retraceString.context.minifiedLineNumber > NO_MATCH
+ ? classContext.lookupFrame(methodName, retraceString.context.minifiedLineNumber)
+ : classContext.lookupFrame(methodName);
+ retraceFrameResult.forEach(
+ element -> {
+ process.accept(
+ element,
+ retraceString.context.withMethodContext(element, retraceFrameResult.isAmbiguous()));
+ });
}
}
@@ -776,7 +778,7 @@
@Override
public List<RetraceString> handleMatch(
- String original, List<RetraceString> strings, Matcher matcher, RetraceApi retracer) {
+ String original, List<RetraceString> strings, Matcher matcher, RetracerImpl retracer) {
final int startOfGroup = matcher.start(captureGroup);
if (startOfGroup == NO_MATCH) {
if (classNameGroupHandler != null) {
@@ -878,7 +880,7 @@
}
}
- private class LineNumberGroup extends RegularExpressionGroup {
+ private static class LineNumberGroup extends RegularExpressionGroup {
@Override
String subExpression() {
@@ -890,7 +892,7 @@
return new RegularExpressionGroupHandler() {
@Override
public List<RetraceString> handleMatch(
- String original, List<RetraceString> strings, Matcher matcher, RetraceApi retracer) {
+ String original, List<RetraceString> strings, Matcher matcher, RetracerImpl retracer) {
final int startOfGroup = matcher.start(captureGroup);
if (startOfGroup == NO_MATCH) {
return strings;
@@ -902,8 +904,7 @@
int lineNumber = Integer.parseInt(lineNumberAsString);
List<RetraceString> retracedStrings = new ArrayList<>();
for (RetraceString retraceString : strings) {
- RetraceClassMemberElement<? extends RetracedMethod> methodContext =
- retraceString.context.methodContext;
+ Element methodContext = retraceString.context.methodContext;
if (methodContext == null) {
if (retraceString.context.classContext == null
|| retraceString.context.methodName == null) {
@@ -961,7 +962,7 @@
@Override
public RetraceStringContext buildInitial(
- RetraceStringContext context, Matcher matcher, RetraceApi retracer) {
+ RetraceStringContext context, Matcher matcher, RetracerImpl retracer) {
if (matcher.start(captureGroup) == NO_MATCH || context.minifiedLineNumber > NO_MATCH) {
return context;
}
@@ -1015,12 +1016,12 @@
return strings;
}
TypeReference typeReference = Reference.returnTypeFromDescriptor(descriptor);
- RetraceTypeResult retracedType = retracer.retrace(typeReference);
+ RetraceTypeResultImpl retracedType = retracer.retraceType(typeReference);
assert !retracedType.isAmbiguous();
for (RetraceString retraceString : strings) {
retracedType.forEach(
element -> {
- RetracedType retracedReference = element.getType();
+ RetracedTypeImpl retracedReference = element.getType();
retraceString.appendRetracedString(
original,
retracedReference.isVoid() ? "void" : retracedReference.getTypeName(),
@@ -1059,10 +1060,10 @@
if (!DescriptorUtils.isDescriptor(descriptor) && !"V".equals(descriptor)) {
return typeName;
}
- final RetraceTypeResult retraceResult =
- retracer.retrace(Reference.returnTypeFromDescriptor(descriptor));
+ final RetraceTypeResultImpl retraceResult =
+ retracer.retraceType(Reference.returnTypeFromDescriptor(descriptor));
assert !retraceResult.isAmbiguous();
- final Box<RetracedType> elementBox = new Box<>();
+ final Box<RetracedTypeImpl> elementBox = new Box<>();
retraceResult.forEach(element -> elementBox.set(element.getType()));
return elementBox.get().getTypeName();
})
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceSourceFileResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceSourceFileResultImpl.java
new file mode 100644
index 0000000..b84b1a6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceSourceFileResultImpl.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+import com.android.tools.r8.retrace.RetraceSourceFileResult;
+
+public class RetraceSourceFileResultImpl implements RetraceSourceFileResult {
+
+ private final String filename;
+ private final boolean synthesized;
+
+ RetraceSourceFileResultImpl(String filename, boolean synthesized) {
+ this.filename = filename;
+ this.synthesized = synthesized;
+ }
+
+ @Override
+ public boolean isSynthesized() {
+ return synthesized;
+ }
+
+ @Override
+ public String getFilename() {
+ return filename;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceTypeResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceTypeResultImpl.java
new file mode 100644
index 0000000..0680800
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceTypeResultImpl.java
@@ -0,0 +1,68 @@
+// Copyright (c) 2019, 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.retrace.internal;
+
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.RetraceTypeResult;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+public class RetraceTypeResultImpl implements RetraceTypeResult {
+
+ private final TypeReference obfuscatedType;
+ private final RetracerImpl retracer;
+
+ private RetraceTypeResultImpl(TypeReference obfuscatedType, RetracerImpl retracer) {
+ this.obfuscatedType = obfuscatedType;
+ this.retracer = retracer;
+ }
+
+ static RetraceTypeResultImpl create(TypeReference obfuscatedType, RetracerImpl retracer) {
+ return new RetraceTypeResultImpl(obfuscatedType, retracer);
+ }
+
+ @Override
+ public Stream<Element> stream() {
+ // Handle void and primitive types as single element results.
+ if (obfuscatedType == null || obfuscatedType.isPrimitive()) {
+ return Stream.of(new ElementImpl(RetracedTypeImpl.create(obfuscatedType)));
+ }
+ if (obfuscatedType.isArray()) {
+ int dimensions = obfuscatedType.asArray().getDimensions();
+ return retracer.retraceType(obfuscatedType.asArray().getBaseType()).stream()
+ .map(
+ baseElement ->
+ new ElementImpl(
+ RetracedTypeImpl.create(baseElement.getType().toArray(dimensions))));
+ }
+ return retracer.retraceClass(obfuscatedType.asClass()).stream()
+ .map(classElement -> new ElementImpl(classElement.getRetracedClass().getRetracedType()));
+ }
+
+ @Override
+ public boolean isAmbiguous() {
+ return false;
+ }
+
+ @Override
+ public RetraceTypeResultImpl forEach(Consumer<Element> resultConsumer) {
+ stream().forEach(resultConsumer);
+ return this;
+ }
+
+ public static class ElementImpl implements RetraceTypeResult.Element {
+
+ private final RetracedTypeImpl retracedType;
+
+ public ElementImpl(RetracedTypeImpl retracedType) {
+ this.retracedType = retracedType;
+ }
+
+ @Override
+ public RetracedTypeImpl getType() {
+ return retracedType;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUtils.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
rename to src/main/java/com/android/tools/r8/retrace/internal/RetraceUtils.java
index e402a80..46e8ddc 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUtils.java
@@ -2,7 +2,7 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -10,6 +10,10 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.RetraceClassResult.Element;
+import com.android.tools.r8.retrace.RetraceSourceFileResult;
+import com.android.tools.r8.retrace.RetracedClass;
+import com.android.tools.r8.retrace.RetracedMethod;
import com.android.tools.r8.retrace.RetracedMethod.KnownRetracedMethod;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -53,14 +57,14 @@
}
public static boolean hasPredictableSourceFileName(String originalClassName, String sourceFile) {
- String synthesizedSourceFileName = getClassSimpleName(originalClassName) + ".java";
+ String synthesizedSourceFileName = getOuterClassSimpleName(originalClassName) + ".java";
return synthesizedSourceFileName.equals(sourceFile);
}
- private static String getClassSimpleName(String clazz) {
- int lastIndexOfPeriod = clazz.lastIndexOf('.');
+ private static String getOuterClassSimpleName(String clazz) {
+ int lastIndexOfPeriod = clazz.lastIndexOf(DescriptorUtils.JAVA_PACKAGE_SEPARATOR);
// Check if we can find a subclass separator.
- int endIndex = clazz.lastIndexOf('$');
+ int endIndex = clazz.indexOf(DescriptorUtils.INNER_CLASS_SEPARATOR, lastIndexOfPeriod);
if (lastIndexOfPeriod > endIndex || endIndex < 0) {
endIndex = clazz.length();
}
@@ -68,10 +72,7 @@
}
static RetraceSourceFileResult getSourceFile(
- RetraceClassResult.Element classElement,
- RetracedClass context,
- String sourceFile,
- RetraceApi retracer) {
+ Element classElement, RetracedClass context, String sourceFile, RetracerImpl retracer) {
// If no context is specified always retrace using the found class element.
if (context == null) {
return classElement.retraceSourceFile(sourceFile);
@@ -79,7 +80,8 @@
if (context.equals(classElement.getRetracedClass())) {
return classElement.retraceSourceFile(sourceFile);
} else {
- RetraceClassResult contextClassResult = retracer.retrace(context.getClassReference());
+ RetraceClassResultImpl contextClassResult =
+ retracer.retraceClass(context.getClassReference());
assert !contextClassResult.isAmbiguous();
if (contextClassResult.hasRetraceResult()) {
Box<RetraceSourceFileResult> retraceSourceFile = new Box<>();
@@ -87,7 +89,7 @@
element -> retraceSourceFile.set(element.retraceSourceFile(sourceFile)));
return retraceSourceFile.get();
} else {
- return new RetraceSourceFileResult(
+ return new RetraceSourceFileResultImpl(
synthesizeFileName(
context.getTypeName(),
classElement.getRetracedClass().getTypeName(),
@@ -118,9 +120,9 @@
// We have no mapping but but file name is unknown, so the best we can do is take the
// name of the obfuscated clazz.
assert minifiedClassName.equals(retracedClassName);
- return getClassSimpleName(minifiedClassName) + "." + extension;
+ return getOuterClassSimpleName(minifiedClassName) + "." + extension;
}
- String newFileName = getClassSimpleName(retracedClassName);
+ String newFileName = getOuterClassSimpleName(retracedClassName);
return newFileName + "." + extension;
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedClassImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedClassImpl.java
new file mode 100644
index 0000000..b2da5d8
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedClassImpl.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.retrace.RetracedClass;
+
+@Keep
+public final class RetracedClassImpl implements RetracedClass {
+
+ private final ClassReference classReference;
+
+ private RetracedClassImpl(ClassReference classReference) {
+ assert classReference != null;
+ this.classReference = classReference;
+ }
+
+ public static RetracedClassImpl create(ClassReference classReference) {
+ return new RetracedClassImpl(classReference);
+ }
+
+ @Override
+ public String getTypeName() {
+ return classReference.getTypeName();
+ }
+
+ @Override
+ public String getBinaryName() {
+ return classReference.getBinaryName();
+ }
+
+ @Override
+ public RetracedTypeImpl getRetracedType() {
+ return RetracedTypeImpl.create(classReference);
+ }
+
+ @Override
+ public ClassReference getClassReference() {
+ return classReference;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ return classReference.equals(((RetracedClassImpl) o).classReference);
+ }
+
+ @Override
+ public int hashCode() {
+ return classReference.hashCode();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedFieldImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedFieldImpl.java
new file mode 100644
index 0000000..aee0cde
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedFieldImpl.java
@@ -0,0 +1,133 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.RetracedField;
+import java.util.Objects;
+
+@Keep
+public abstract class RetracedFieldImpl implements RetracedField {
+
+ private RetracedFieldImpl() {}
+
+ @Override
+ public boolean isUnknown() {
+ return true;
+ }
+
+ @Override
+ public final boolean isKnown() {
+ return !isUnknown();
+ }
+
+ @Override
+ public KnownRetracedFieldImpl asKnown() {
+ return null;
+ }
+
+ public static final class KnownRetracedFieldImpl extends RetracedFieldImpl
+ implements KnownRetracedField {
+
+ private final FieldReference fieldReference;
+
+ private KnownRetracedFieldImpl(FieldReference fieldReference) {
+ this.fieldReference = fieldReference;
+ }
+
+ @Override
+ public boolean isUnknown() {
+ return false;
+ }
+
+ @Override
+ public KnownRetracedFieldImpl asKnown() {
+ return this;
+ }
+
+ @Override
+ public RetracedClassImpl getHolderClass() {
+ return RetracedClassImpl.create(fieldReference.getHolderClass());
+ }
+
+ @Override
+ public String getFieldName() {
+ return fieldReference.getFieldName();
+ }
+
+ @Override
+ public TypeReference getFieldType() {
+ return fieldReference.getFieldType();
+ }
+
+ @Override
+ public FieldReference getFieldReference() {
+ return fieldReference;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ KnownRetracedFieldImpl that = (KnownRetracedFieldImpl) o;
+ return fieldReference.equals(that.fieldReference);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fieldReference);
+ }
+ }
+
+ public static final class UnknownRetracedField extends RetracedFieldImpl {
+
+ private final FieldDefinition fieldDefinition;
+
+ private UnknownRetracedField(FieldDefinition fieldDefinition) {
+ this.fieldDefinition = fieldDefinition;
+ }
+
+ @Override
+ public RetracedClassImpl getHolderClass() {
+ return RetracedClassImpl.create(fieldDefinition.getHolderClass());
+ }
+
+ @Override
+ public String getFieldName() {
+ return fieldDefinition.getName();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ UnknownRetracedField that = (UnknownRetracedField) o;
+ return fieldDefinition.equals(that.fieldDefinition);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fieldDefinition);
+ }
+ }
+
+ static RetracedFieldImpl create(FieldReference fieldReference) {
+ return new KnownRetracedFieldImpl(fieldReference);
+ }
+
+ static RetracedFieldImpl create(FieldDefinition fieldDefinition) {
+ return new UnknownRetracedField(fieldDefinition);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodImpl.java
new file mode 100644
index 0000000..998fe7d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodImpl.java
@@ -0,0 +1,175 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.RetracedMethod;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+@Keep
+public abstract class RetracedMethodImpl implements RetracedMethod {
+
+ private static final int NO_POSITION = -1;
+
+ private RetracedMethodImpl() {}
+
+ @Override
+ public boolean isUnknown() {
+ return true;
+ }
+
+ @Override
+ public final boolean isKnown() {
+ return !isUnknown();
+ }
+
+ @Override
+ public KnownRetracedMethodImpl asKnown() {
+ return null;
+ }
+
+ public static final class KnownRetracedMethodImpl extends RetracedMethodImpl
+ implements KnownRetracedMethod {
+
+ private final MethodReference methodReference;
+ private final int position;
+
+ private KnownRetracedMethodImpl(MethodReference methodReference, int position) {
+ assert methodReference != null;
+ this.methodReference = methodReference;
+ this.position = position;
+ }
+
+ @Override
+ public boolean isUnknown() {
+ return false;
+ }
+
+ @Override
+ public boolean isVoid() {
+ return methodReference.getReturnType() == null;
+ }
+
+ @Override
+ public KnownRetracedMethodImpl asKnown() {
+ return this;
+ }
+
+ @Override
+ public RetracedClassImpl getHolderClass() {
+ return RetracedClassImpl.create(methodReference.getHolderClass());
+ }
+
+ @Override
+ public String getMethodName() {
+ return methodReference.getMethodName();
+ }
+
+ @Override
+ public boolean hasPosition() {
+ return position != NO_POSITION;
+ }
+
+ @Override
+ public int getOriginalPositionOrDefault(int defaultPosition) {
+ return hasPosition() ? position : defaultPosition;
+ }
+
+ @Override
+ public TypeReference getReturnType() {
+ assert !isVoid();
+ return methodReference.getReturnType();
+ }
+
+ @Override
+ public List<TypeReference> getFormalTypes() {
+ return methodReference.getFormalTypes();
+ }
+
+ @Override
+ public MethodReference getMethodReference() {
+ return methodReference;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ KnownRetracedMethodImpl that = (KnownRetracedMethodImpl) o;
+ return position == that.position && methodReference.equals(that.methodReference);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(methodReference, position);
+ }
+ }
+
+ public static final class UnknownRetracedMethodImpl extends RetracedMethodImpl {
+
+ private final MethodDefinition methodDefinition;
+ private final int position;
+
+ private UnknownRetracedMethodImpl(MethodDefinition methodDefinition, int position) {
+ this.methodDefinition = methodDefinition;
+ this.position = position;
+ }
+
+ @Override
+ public RetracedClassImpl getHolderClass() {
+ return RetracedClassImpl.create(methodDefinition.getHolderClass());
+ }
+
+ @Override
+ public String getMethodName() {
+ return methodDefinition.getName();
+ }
+
+ @Override
+ public boolean hasPosition() {
+ return position != NO_POSITION;
+ }
+
+ @Override
+ public int getOriginalPositionOrDefault(int defaultPosition) {
+ return hasPosition() ? position : defaultPosition;
+ }
+
+ public Optional<MethodReference> getMethodReference() {
+ if (!methodDefinition.isFullMethodDefinition()) {
+ return Optional.empty();
+ }
+ return Optional.of(methodDefinition.asFullMethodDefinition().getMethodReference());
+ }
+ }
+
+ static RetracedMethodImpl create(MethodDefinition methodDefinition) {
+ return create(methodDefinition, NO_POSITION);
+ }
+
+ static RetracedMethodImpl create(MethodDefinition methodDefinition, int position) {
+ if (methodDefinition.isFullMethodDefinition()) {
+ return new KnownRetracedMethodImpl(
+ methodDefinition.asFullMethodDefinition().getMethodReference(), position);
+ }
+ return new UnknownRetracedMethodImpl(methodDefinition, position);
+ }
+
+ static RetracedMethodImpl create(MethodReference methodReference) {
+ return create(methodReference, NO_POSITION);
+ }
+
+ static RetracedMethodImpl create(MethodReference methodReference, int position) {
+ return new KnownRetracedMethodImpl(methodReference, position);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedTypeImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedTypeImpl.java
new file mode 100644
index 0000000..8162e05
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedTypeImpl.java
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.RetracedType;
+import java.util.Objects;
+
+@Keep
+public final class RetracedTypeImpl implements RetracedType {
+
+ private final TypeReference typeReference;
+
+ private RetracedTypeImpl(TypeReference typeReference) {
+ this.typeReference = typeReference;
+ }
+
+ static RetracedTypeImpl create(TypeReference typeReference) {
+ return new RetracedTypeImpl(typeReference);
+ }
+
+ @Override
+ public boolean isVoid() {
+ return typeReference == null;
+ }
+
+ @Override
+ public TypeReference toArray(int dimensions) {
+ return Reference.array(typeReference, dimensions);
+ }
+
+ @Override
+ public String getTypeName() {
+ assert !isVoid();
+ return typeReference.getTypeName();
+ }
+
+ @Override
+ public TypeReference getTypeReference() {
+ return typeReference;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ return typeReference.equals(((RetracedTypeImpl) o).typeReference);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(typeReference);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
new file mode 100644
index 0000000..eed4f28
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
@@ -0,0 +1,70 @@
+// Copyright (c) 2019, 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.retrace.internal;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.InvalidMappingFileException;
+import com.android.tools.r8.retrace.RetraceCommand.ProguardMapProducer;
+import com.android.tools.r8.retrace.Retracer;
+
+/** A default implementation for the retrace api using the ClassNameMapper defined in R8. */
+public class RetracerImpl implements Retracer {
+
+ private final ClassNameMapper classNameMapper;
+
+ private RetracerImpl(ClassNameMapper classNameMapper) {
+ this.classNameMapper = classNameMapper;
+ assert classNameMapper != null;
+ }
+
+ public static RetracerImpl create(
+ ProguardMapProducer proguardMapProducer, DiagnosticsHandler diagnosticsHandler) {
+ if (proguardMapProducer instanceof DirectClassNameMapperProguardMapProducer) {
+ return new RetracerImpl(
+ ((DirectClassNameMapperProguardMapProducer) proguardMapProducer).getClassNameMapper());
+ }
+ try {
+ ClassNameMapper classNameMapper =
+ ClassNameMapper.mapperFromString(proguardMapProducer.get(), diagnosticsHandler);
+ return new RetracerImpl(classNameMapper);
+ } catch (Throwable throwable) {
+ throw new InvalidMappingFileException(throwable);
+ }
+ }
+
+ @Override
+ public RetraceMethodResultImpl retraceMethod(MethodReference methodReference) {
+ return retraceClass(methodReference.getHolderClass())
+ .lookupMethod(methodReference.getMethodName());
+ }
+
+ @Override
+ public RetraceFrameResultImpl retraceFrame(MethodReference methodReference, int position) {
+ return retraceClass(methodReference.getHolderClass())
+ .lookupMethod(methodReference.getMethodName())
+ .narrowByPosition(position);
+ }
+
+ @Override
+ public RetraceFieldResultImpl retraceField(FieldReference fieldReference) {
+ return retraceClass(fieldReference.getHolderClass()).lookupField(fieldReference.getFieldName());
+ }
+
+ @Override
+ public RetraceClassResultImpl retraceClass(ClassReference classReference) {
+ return RetraceClassResultImpl.create(
+ classReference, classNameMapper.getClassNaming(classReference.getTypeName()), this);
+ }
+
+ @Override
+ public RetraceTypeResultImpl retraceType(TypeReference typeReference) {
+ return RetraceTypeResultImpl.create(typeReference, this);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
new file mode 100644
index 0000000..c21b92d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
@@ -0,0 +1,207 @@
+// Copyright (c) 2020, 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.retrace.internal;
+
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.RetraceStackTraceProxy;
+import com.android.tools.r8.retrace.RetracedClass;
+import com.android.tools.r8.retrace.RetracedMethod;
+import com.android.tools.r8.retrace.StackTraceElementProxy;
+import com.android.tools.r8.retrace.StackTraceElementProxyRetracer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class StackTraceElementProxyRetracerImpl<T extends StackTraceElementProxy<?>>
+ implements StackTraceElementProxyRetracer<T> {
+
+ private final RetracerImpl retracer;
+
+ public StackTraceElementProxyRetracerImpl(RetracerImpl retracer) {
+ this.retracer = retracer;
+ }
+
+ @Override
+ public Stream<RetraceStackTraceProxyImpl<T>> retrace(T element) {
+ if (!element.hasClassName()) {
+ return Stream.of(RetraceStackTraceProxyImpl.builder(element).build());
+ }
+ RetraceClassResultImpl classResult =
+ retracer.retraceClass(Reference.classFromTypeName(element.className()));
+ List<RetraceStackTraceProxyImpl<T>> retracedProxies = new ArrayList<>();
+ if (!element.hasMethodName()) {
+ classResult.forEach(
+ classElement -> {
+ RetraceStackTraceProxyImpl.Builder<T> proxy =
+ RetraceStackTraceProxyImpl.builder(element)
+ .setRetracedClassElement(classElement.getRetracedClass())
+ .setAmbiguous(classResult.isAmbiguous());
+ if (element.hasFileName()) {
+ proxy.setSourceFile(classElement.retraceSourceFile(element.fileName()).getFilename());
+ }
+ retracedProxies.add(proxy.build());
+ });
+ } else {
+ RetraceFrameResultImpl frameResult =
+ element.hasLineNumber()
+ ? classResult.lookupFrame(element.methodName(), element.lineNumber())
+ : classResult.lookupFrame(element.methodName());
+ frameResult.forEach(
+ frameElement -> {
+ frameElement.visitFrames(
+ (frame, index) -> {
+ RetraceStackTraceProxyImpl.Builder<T> proxy =
+ RetraceStackTraceProxyImpl.builder(element)
+ .setRetracedClassElement(frame.getHolderClass())
+ .setRetracedMethodElement(frame)
+ .setAmbiguous(frameResult.isAmbiguous() && index == 0);
+ if (element.hasLineNumber()) {
+ proxy.setLineNumber(frame.getOriginalPositionOrDefault(element.lineNumber()));
+ }
+ if (element.hasFileName()) {
+ proxy.setSourceFile(
+ frameElement.retraceSourceFile(frame, element.fileName()).getFilename());
+ }
+ retracedProxies.add(proxy.build());
+ });
+ });
+ }
+ return retracedProxies.stream();
+ }
+
+ public static class RetraceStackTraceProxyImpl<T extends StackTraceElementProxy<?>>
+ implements RetraceStackTraceProxy<T> {
+
+ private final T originalItem;
+ private final RetracedClass retracedClass;
+ private final RetracedMethod retracedMethod;
+ private final String sourceFile;
+ private final int lineNumber;
+ private final boolean isAmbiguous;
+
+ private RetraceStackTraceProxyImpl(
+ T originalItem,
+ RetracedClass retracedClass,
+ RetracedMethod retracedMethod,
+ String sourceFile,
+ int lineNumber,
+ boolean isAmbiguous) {
+ assert originalItem != null;
+ this.originalItem = originalItem;
+ this.retracedClass = retracedClass;
+ this.retracedMethod = retracedMethod;
+ this.sourceFile = sourceFile;
+ this.lineNumber = lineNumber;
+ this.isAmbiguous = isAmbiguous;
+ }
+
+ @Override
+ public boolean isAmbiguous() {
+ return isAmbiguous;
+ }
+
+ @Override
+ public boolean hasRetracedClass() {
+ return retracedClass != null;
+ }
+
+ @Override
+ public boolean hasRetracedMethod() {
+ return retracedMethod != null;
+ }
+
+ @Override
+ public boolean hasSourceFile() {
+ return sourceFile != null;
+ }
+
+ @Override
+ public boolean hasLineNumber() {
+ return lineNumber != -1;
+ }
+
+ @Override
+ public T getOriginalItem() {
+ return originalItem;
+ }
+
+ @Override
+ public RetracedClass getRetracedClass() {
+ return retracedClass;
+ }
+
+ @Override
+ public RetracedMethod getRetracedMethod() {
+ return retracedMethod;
+ }
+
+ @Override
+ public String getSourceFile() {
+ return sourceFile;
+ }
+
+ private static <T extends StackTraceElementProxy<?>> Builder<T> builder(T originalElement) {
+ return new Builder<>(originalElement);
+ }
+
+ @Override
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ private static class Builder<T extends StackTraceElementProxy<?>> {
+
+ private final T originalElement;
+ private RetracedClass classContext;
+ private RetracedMethod methodContext;
+ private String sourceFile;
+ private int lineNumber = -1;
+ private boolean isAmbiguous;
+
+ private Builder(T originalElement) {
+ this.originalElement = originalElement;
+ }
+
+ private Builder<T> setRetracedClassElement(RetracedClass retracedClass) {
+ this.classContext = retracedClass;
+ return this;
+ }
+
+ private Builder<T> setRetracedMethodElement(RetracedMethod methodElement) {
+ this.methodContext = methodElement;
+ return this;
+ }
+
+ private Builder<T> setSourceFile(String sourceFile) {
+ this.sourceFile = sourceFile;
+ return this;
+ }
+
+ private Builder<T> setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ return this;
+ }
+
+ private Builder<T> setAmbiguous(boolean ambiguous) {
+ this.isAmbiguous = ambiguous;
+ return this;
+ }
+
+ private RetraceStackTraceProxyImpl<T> build() {
+ RetracedClass retracedClass = classContext;
+ if (methodContext != null) {
+ retracedClass = methodContext.getHolderClass();
+ }
+ return new RetraceStackTraceProxyImpl<>(
+ originalElement,
+ retracedClass,
+ methodContext,
+ sourceFile != null ? sourceFile : null,
+ lineNumber,
+ isAmbiguous);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/StackTraceElementStringProxy.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
similarity index 90%
rename from src/main/java/com/android/tools/r8/retrace/StackTraceElementStringProxy.java
rename to src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
index dc21cbe..202d297 100644
--- a/src/main/java/com/android/tools/r8/retrace/StackTraceElementStringProxy.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
@@ -2,12 +2,13 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
-import static com.android.tools.r8.retrace.PlainStackTraceVisitor.firstNonWhiteSpaceCharacterFromIndex;
-import static com.android.tools.r8.retrace.StackTraceElementStringProxy.StringIndex.noIndex;
+import static com.android.tools.r8.retrace.internal.PlainStackTraceVisitor.firstNonWhiteSpaceCharacterFromIndex;
+import static com.android.tools.r8.retrace.internal.StackTraceElementStringProxy.StringIndex.noIndex;
-import com.android.tools.r8.retrace.StackTraceElementProxyRetracer.RetraceStackTraceProxy;
+import com.android.tools.r8.retrace.StackTraceElementProxy;
+import com.android.tools.r8.retrace.internal.StackTraceElementProxyRetracerImpl.RetraceStackTraceProxyImpl;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
@@ -88,7 +89,8 @@
}
public String toRetracedItem(
- RetraceStackTraceProxy<StackTraceElementStringProxy> retracedProxy, boolean printAmbiguous) {
+ RetraceStackTraceProxyImpl<StackTraceElementStringProxy> retracedProxy,
+ boolean printAmbiguous) {
StringBuilder sb = new StringBuilder();
int lastSeenIndex = 0;
if (retracedProxy.isAmbiguous() && printAmbiguous) {
@@ -203,7 +205,7 @@
private final int startIndex;
private final int endIndex;
private final BiFunction<
- RetraceStackTraceProxy<StackTraceElementStringProxy>,
+ RetraceStackTraceProxyImpl<StackTraceElementStringProxy>,
StackTraceElementStringProxy,
String>
retracedString;
@@ -212,7 +214,7 @@
int startIndex,
int endIndex,
BiFunction<
- RetraceStackTraceProxy<StackTraceElementStringProxy>,
+ RetraceStackTraceProxyImpl<StackTraceElementStringProxy>,
StackTraceElementStringProxy,
String>
retracedString) {
diff --git a/src/main/java/com/android/tools/r8/retrace/StackTraceVisitor.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceVisitor.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/retrace/StackTraceVisitor.java
rename to src/main/java/com/android/tools/r8/retrace/internal/StackTraceVisitor.java
index fd9c822..dfe937a 100644
--- a/src/main/java/com/android/tools/r8/retrace/StackTraceVisitor.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceVisitor.java
@@ -2,8 +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.
-package com.android.tools.r8.retrace;
+package com.android.tools.r8.retrace.internal;
+import com.android.tools.r8.retrace.StackTraceElementProxy;
import java.util.function.Consumer;
public interface StackTraceVisitor<T extends StackTraceElementProxy<?>> {
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index d5bc317..7c6d911 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -905,6 +905,10 @@
return this;
}
+ public boolean isClassInliningAllowed(DexProgramClass clazz) {
+ return !isPinned(clazz) && !neverClassInline.contains(clazz.getType());
+ }
+
public boolean isMinificationAllowed(DexReference reference) {
return options().isMinificationEnabled()
&& keepInfo.getInfo(reference, this).isMinificationAllowed(options());
@@ -938,6 +942,11 @@
return keepInfo.isPinned(reference, this);
}
+ public boolean isPinned(DexDefinition definition) {
+ assert definition != null;
+ return isPinned(definition.toReference());
+ }
+
public boolean hasPinnedInstanceInitializer(DexType type) {
assert type.isClassType();
DexProgramClass clazz = asProgramClassOrNull(definitionFor(type));
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index d0834d5..9ccbf5e 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -223,7 +223,10 @@
keepClassInfo.forEach(
(type, info) -> {
DexType newType = lens.lookupType(type);
- assert newType == type || !info.isPinned() || info.isMinificationAllowed(options);
+ assert newType == type
+ || !info.isPinned()
+ || info.isMinificationAllowed(options)
+ || info.isRepackagingAllowed(options);
KeepClassInfo previous = newClassInfo.put(newType, info);
assert previous == null;
});
diff --git a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
index 28d1ed5..32ca59a 100644
--- a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
@@ -166,16 +166,28 @@
public static void withMainProgramHandler(MainAction action) {
try {
action.run();
- } catch (CompilationFailedException | AbortException e) {
+ } catch (CompilationFailedException e) {
+ throw exitWithError(e, e.getCause());
+ } catch (RuntimeException e) {
+ throw exitWithError(e, e);
+ }
+ }
+
+ private static RuntimeException exitWithError(Throwable e, Throwable cause) {
+ if (isExpectedException(cause)) {
// Detail of the errors were already reported
System.err.println("Compilation failed");
System.exit(STATUS_ERROR);
- } catch (RuntimeException e) {
- System.err.println("Compilation failed with an internal error.");
- Throwable cause = e.getCause() == null ? e : e.getCause();
- cause.printStackTrace();
- System.exit(STATUS_ERROR);
+ throw null;
}
+ System.err.println("Compilation failed with an internal error.");
+ e.printStackTrace();
+ System.exit(STATUS_ERROR);
+ throw null;
+ }
+
+ private static boolean isExpectedException(Throwable e) {
+ return e instanceof CompilationError || e instanceof AbortException;
}
// We should try to avoid the use of this extraction as it signifies a point where we don't have
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 c1fe00e..f4c003e 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -352,12 +352,10 @@
.setCompilationMode(debug ? CompilationMode.DEBUG : CompilationMode.RELEASE)
.setBackend(isGeneratingClassFiles() ? Backend.CF : Backend.DEX)
.setHasChecksums(encodeChecksums);
- // Compiling with D8 and L8 is always with a min API level and desugaring to that level. If
- // desugaring is explicitly turned off for D8 the input is expected to already have been
- // desugared to the specified min API level. For R8 desugaring is optional.
- if (tool == Tool.D8
- || tool == Tool.L8
- || (tool == Tool.R8 && desugarState != DesugarState.OFF)) {
+ // The marker records the min API if any desugaring happens or if the compiler generates dex
+ // since the output depends on the min API in this case. There is basically no min API entry
+ // in R8 cf to cf.
+ if (isGeneratingDex() || desugarState == DesugarState.ON) {
marker.setMinApi(minApiLevel);
}
if (desugaredLibraryConfiguration.getIdentifier() != null) {
@@ -1307,7 +1305,6 @@
public PrintStream whyAreYouNotInliningConsumer = System.out;
public boolean trackDesugaredAPIConversions =
System.getProperty("com.android.tools.r8.trackDesugaredAPIConversions") != null;
- public boolean forceLibBackportsInL8CfToCf = false;
public boolean enumUnboxingRewriteJavaCGeneratedMethod = false;
// TODO(b/154793333): Enable assertions always when resolved.
public boolean assertConsistentRenamingOfSignature = false;
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 2272f50..f2358c5 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -48,7 +48,7 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.Range;
import com.android.tools.r8.naming.mappinginformation.FileNameInformation;
-import com.android.tools.r8.retrace.RetraceUtils;
+import com.android.tools.r8.retrace.internal.RetraceUtils;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.google.common.base.Suppliers;
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 43f4f57..4e476e3 100644
--- a/src/main/java/com/android/tools/r8/utils/Reporter.java
+++ b/src/main/java/com/android/tools/r8/utils/Reporter.java
@@ -11,10 +11,38 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.DiagnosticsLevel;
import com.android.tools.r8.errors.Unreachable;
+import java.util.ArrayList;
+import java.util.List;
public class Reporter implements DiagnosticsHandler {
+ private static class DiagnosticsLevelMapping {
+ private final DiagnosticsLevel from;
+ private final DiagnosticsLevel to;
+ private final String diagnosticsClassName;
+
+ public DiagnosticsLevelMapping(
+ DiagnosticsLevel from, DiagnosticsLevel to, String diagnosticsClassName) {
+ this.from = from;
+ this.to = to;
+ this.diagnosticsClassName = diagnosticsClassName;
+ }
+
+ public DiagnosticsLevel map(DiagnosticsLevel level, Diagnostic diagnostic) {
+ if (level != from) {
+ return level;
+ }
+ if (diagnosticsClassName.length() == 0
+ || diagnosticsClassName.equals(diagnostic.getClass().getSimpleName())
+ || diagnosticsClassName.equals(diagnostic.getClass().getTypeName())) {
+ return to;
+ }
+ return level;
+ }
+ }
+
private final DiagnosticsHandler clientHandler;
+ private final List<DiagnosticsLevelMapping> diagnosticsLevelMapping = new ArrayList<>();
private AbortException abort = null;
public Reporter() {
@@ -31,6 +59,7 @@
if (level != null) {
DiagnosticsLevel modifiedLevel = clientHandler.modifyDiagnosticsLevel(level, diagnostic);
level = modifiedLevel != null ? modifiedLevel : level;
+ level = mapDiagnosticsLevel(level, diagnostic);
} else {
level = ERROR;
}
@@ -55,6 +84,10 @@
handleDiagnostic(INFO, info);
}
+ public void info(String message) {
+ info(new StringDiagnostic(message));
+ }
+
@Override
public synchronized void warning(Diagnostic warning) {
handleDiagnostic(WARNING, warning);
@@ -94,4 +127,16 @@
throw new RuntimeException(abort);
}
}
+
+ private DiagnosticsLevel mapDiagnosticsLevel(DiagnosticsLevel level, Diagnostic diagnostic) {
+ for (DiagnosticsLevelMapping diagnosticsLevelMapping : diagnosticsLevelMapping) {
+ level = diagnosticsLevelMapping.map(level, diagnostic);
+ }
+ return level;
+ }
+
+ public void addDiagnosticsLevelMapping(
+ DiagnosticsLevel from, String diagnosticsClassName, DiagnosticsLevel to) {
+ diagnosticsLevelMapping.add(new DiagnosticsLevelMapping(from, to, diagnosticsClassName));
+ }
}
diff --git a/src/main/keep.txt b/src/main/keep.txt
index 84423da..f8bbc12 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -21,6 +21,7 @@
-keepattributes SourceFile, LineNumberTable, InnerClasses, EnclosingMethod, Exceptions, Signature
-keeppackagenames com.android.tools.r8
+-repackageclasses com.android.tools.r8.internal
# Compatibility command line program used by the Android Platform build.
-keep public class com.android.tools.r8.compatproguard.CompatProguard { public static void main(java.lang.String[]); }
diff --git a/src/test/java/com/android/tools/r8/CommandTestBase.java b/src/test/java/com/android/tools/r8/CommandTestBase.java
new file mode 100644
index 0000000..dcfbeca
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/CommandTestBase.java
@@ -0,0 +1,315 @@
+// Copyright (c) 2020, 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public abstract class CommandTestBase<C extends BaseCompilerCommand> extends TestBase {
+ private void mapDiagnosticsMissingArguments(String... args) throws Exception {
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ "Missing argument(s) for --map-diagnostics", handler -> parse(handler, args));
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void mapDiagnosticsMissingArguments() throws Exception {
+ mapDiagnosticsMissingArguments("--map-diagnostics");
+ mapDiagnosticsMissingArguments("--map-diagnostics", "error");
+ mapDiagnosticsMissingArguments("--map-diagnostics", "warning");
+ mapDiagnosticsMissingArguments("--map-diagnostics", "info");
+ mapDiagnosticsMissingArguments("--map-diagnostics", "xxx");
+ }
+
+ private void mapDiagnosticsInvalidArguments(String... args) throws Exception {
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ "Invalid diagnostics level 'xxx'", handler -> parse(handler, args));
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void mapDiagnosticsInvalidArguments() throws Exception {
+ mapDiagnosticsInvalidArguments("--map-diagnostics", "error", "xxx");
+ mapDiagnosticsInvalidArguments("--map-diagnostics", "warning", "xxx");
+ mapDiagnosticsInvalidArguments("--map-diagnostics", "info", "xxx");
+ mapDiagnosticsInvalidArguments("--map-diagnostics", "xxx", "xxx");
+ mapDiagnosticsInvalidArguments("--map-diagnostics", "xxx", "error");
+ mapDiagnosticsInvalidArguments("--map-diagnostics", "xxx", "warning");
+ mapDiagnosticsInvalidArguments("--map-diagnostics", "xxx", "info");
+ mapDiagnosticsInvalidArguments("--debug", "--map-diagnostics", "error", "xxx", "--debug");
+ }
+
+ @Test
+ public void mapDiagnosticsInvalidArgumentsMoreErrors() throws Exception {
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ ImmutableList.of("Invalid diagnostics level 'xxx'", "Unknown option: --xxx"),
+ handler -> parse(handler, "--debug", "--map-diagnostics", "error", "xxx", "--xxx"));
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void errorsToWarnings() throws Exception {
+ DiagnosticsChecker.checkWarningsContains(
+ "Error",
+ handler -> {
+ C command = parseWithRequiredArgs(handler, "--map-diagnostics", "error", "warning");
+ command.getReporter().error("Error");
+ });
+
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ "Test diagnostic",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(handler, "--map-diagnostics:a.b.C", "error", "warning");
+ command.getReporter().error(new TestDiagnostic());
+ try {
+ command.getReporter().failIfPendingErrors();
+ } catch (RuntimeException e) {
+ throw new CompilationFailedException();
+ }
+ });
+ fail("Failure expected");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+
+ DiagnosticsChecker.checkWarningsContains(
+ "Test diagnostic",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(
+ handler,
+ "--map-diagnostics:com.android.tools.r8.TestDiagnostic",
+ "error",
+ "warning");
+ command.getReporter().error(new TestDiagnostic());
+ });
+
+ DiagnosticsChecker.checkWarningsContains(
+ "Test diagnostic",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(
+ handler, "--map-diagnostics:TestDiagnostic", "error", "warning");
+ command.getReporter().error(new TestDiagnostic());
+ });
+ }
+
+ @Test
+ public void errorsToInfo() throws Exception {
+ DiagnosticsChecker.checkInfosContains(
+ "Error",
+ handler -> {
+ C command = parseWithRequiredArgs(handler, "--map-diagnostics", "error", "info");
+ command.getReporter().error("Error");
+ });
+
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ "Test diagnostic",
+ handler -> {
+ C command = parseWithRequiredArgs(handler, "--map-diagnostics:a.b.C", "error", "info");
+ command.getReporter().error(new TestDiagnostic());
+ try {
+ command.getReporter().failIfPendingErrors();
+ } catch (RuntimeException e) {
+ throw new CompilationFailedException();
+ }
+ });
+ fail("Failure expected");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+
+ DiagnosticsChecker.checkInfosContains(
+ "Test diagnostic",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(handler, "--map-diagnostics:TestDiagnostic", "error", "info");
+ command.getReporter().error(new TestDiagnostic());
+ });
+ }
+
+ @Test
+ public void warningsToInfo() throws Exception {
+ DiagnosticsChecker.checkInfosContains(
+ "Warning",
+ handler -> {
+ C command = parseWithRequiredArgs(handler, "--map-diagnostics", "warning", "info");
+ command.getReporter().warning("Warning");
+ });
+
+ DiagnosticsChecker.checkInfosContains(
+ "Test diagnostic",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(handler, "--map-diagnostics:TestDiagnostic", "warning", "info");
+ command.getReporter().warning(new TestDiagnostic());
+ });
+ }
+
+ @Test
+ public void warningsToError() throws Exception {
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ "Warning",
+ handler -> {
+ C command = parseWithRequiredArgs(handler, "--map-diagnostics", "warning", "error");
+ command.getReporter().warning("Warning");
+ try {
+ command.getReporter().failIfPendingErrors();
+ } catch (RuntimeException e) {
+ throw new CompilationFailedException();
+ }
+ });
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ "Test diagnostic",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(
+ handler, "--map-diagnostics:TestDiagnostic", "warning", "error");
+ command.getReporter().warning(new TestDiagnostic());
+ try {
+ command.getReporter().failIfPendingErrors();
+ } catch (RuntimeException e) {
+ throw new CompilationFailedException();
+ }
+ });
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void errorsToWarningsWarningsToInfos() throws Exception {
+ DiagnosticsChecker.checkInfosContains(
+ "Error",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(
+ handler,
+ "--map-diagnostics",
+ "error",
+ "warning",
+ "--map-diagnostics",
+ "warning",
+ "info");
+ command.getReporter().error("Error");
+ });
+
+ DiagnosticsChecker.checkInfosContains(
+ "Test diagnostic",
+ handler -> {
+ C command =
+ parseWithRequiredArgs(
+ handler,
+ "--map-diagnostics:TestDiagnostic",
+ "error",
+ "warning",
+ "--map-diagnostics",
+ "warning",
+ "info");
+ command.getReporter().error(new TestDiagnostic());
+ });
+ }
+
+ @Test
+ public void warningsToInfosErrorsToWarnings() throws Exception {
+ DiagnosticsChecker.checkDiagnostics(
+ diagnostics -> {
+ assertEquals(0, diagnostics.errors.size());
+ diagnostics.checkWarningsContains("Error");
+ diagnostics.checkInfosContains("Warning");
+ },
+ handler -> {
+ C command =
+ parseWithRequiredArgs(
+ handler,
+ "--map-diagnostics",
+ "warning",
+ "info",
+ "--map-diagnostics",
+ "error",
+ "warning");
+ command.getReporter().error("Error");
+ command.getReporter().warning("Warning");
+ });
+
+ DiagnosticsChecker.checkDiagnostics(
+ diagnostics -> {
+ assertEquals(0, diagnostics.errors.size());
+ diagnostics.checkWarningsContains("Test diagnostic");
+ diagnostics.checkInfosContains("Test diagnostic");
+ },
+ handler -> {
+ C command =
+ parseWithRequiredArgs(
+ handler,
+ "--map-diagnostics:TestDiagnostic",
+ "warning",
+ "info",
+ "--map-diagnostics:TestDiagnostic",
+ "error",
+ "warning");
+ command.getReporter().error(new TestDiagnostic());
+ command.getReporter().warning(new TestDiagnostic());
+ });
+ }
+
+ private String[] prepareArgs(String[] args) {
+ String[] actualTestArgs;
+ String[] additionalTestArgs = requiredArgsForTest();
+ if (additionalTestArgs.length > 0) {
+ actualTestArgs = new String[args.length + additionalTestArgs.length];
+ System.arraycopy(additionalTestArgs, 0, actualTestArgs, 0, additionalTestArgs.length);
+ System.arraycopy(args, 0, actualTestArgs, additionalTestArgs.length, args.length);
+ } else {
+ actualTestArgs = args;
+ }
+ return actualTestArgs;
+ }
+
+ private C parseWithRequiredArgs(String... args) throws CompilationFailedException {
+ return parse(prepareArgs(args));
+ }
+
+ private C parseWithRequiredArgs(DiagnosticsHandler handler, String... args)
+ throws CompilationFailedException {
+ return parse(handler, prepareArgs(args));
+ }
+
+ /**
+ * Tests in this class are executed for all of D8, R8 and L8. When testing arguments this can add
+ * additional required arguments to all tests
+ */
+ abstract String[] requiredArgsForTest();
+
+ abstract C parse(String... args) throws CompilationFailedException;
+
+ abstract C parse(DiagnosticsHandler handler, String... args) throws CompilationFailedException;
+}
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index 5be6b85..9b80b80 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -43,7 +43,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class D8CommandTest extends TestBase {
+public class D8CommandTest extends CommandTestBase<D8Command> {
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -657,12 +657,18 @@
numThreadsOptionInvalid("two");
}
- private D8Command parse(String... args) throws CompilationFailedException {
+ @Override
+ String[] requiredArgsForTest() {
+ return new String[0];
+ }
+
+ @Override
+ D8Command parse(String... args) throws CompilationFailedException {
return D8Command.parse(args, EmbeddedOrigin.INSTANCE).build();
}
- private D8Command parse(DiagnosticsHandler handler, String... args)
- throws CompilationFailedException {
+ @Override
+ D8Command parse(DiagnosticsHandler handler, String... args) throws CompilationFailedException {
return D8Command.parse(args, EmbeddedOrigin.INSTANCE, handler).build();
}
}
diff --git a/src/test/java/com/android/tools/r8/DiagnosticsChecker.java b/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
index b62416f..730d952 100644
--- a/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
+++ b/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
@@ -14,13 +14,16 @@
import com.android.tools.r8.position.TextPosition;
import com.android.tools.r8.position.TextRange;
import com.android.tools.r8.utils.ListUtils;
+import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
// Helper to check that a particular error occurred.
public class DiagnosticsChecker implements DiagnosticsHandler {
+
public List<Diagnostic> errors = new ArrayList<>();
public List<Diagnostic> warnings = new ArrayList<>();
public List<Diagnostic> infos = new ArrayList<>();
@@ -41,6 +44,7 @@
}
public interface FailingRunner {
+
void run(DiagnosticsHandler handler) throws CompilationFailedException;
}
@@ -56,18 +60,38 @@
diagnostics.stream().anyMatch(d -> d.getDiagnosticMessage().contains(snippet)));
}
+ public void checkWarningsContains(String snippet) {
+ checkContains(snippet, warnings);
+ }
+
+ public void checkInfosContains(String snippet) {
+ checkContains(snippet, infos);
+ }
+
public static void checkErrorsContains(String snippet, FailingRunner runner)
throws CompilationFailedException {
+ checkErrorsContains(ImmutableList.of(snippet), runner);
+ }
+
+ public static void checkErrorsContains(Collection<String> snippets, FailingRunner runner)
+ throws CompilationFailedException {
DiagnosticsChecker handler = new DiagnosticsChecker();
try {
runner.run(handler);
fail("Failure expected");
} catch (CompilationFailedException e) {
- checkContains(snippet, handler.errors);
+ snippets.forEach(snippet -> checkContains(snippet, handler.errors));
throw e;
}
}
+ public static void checkDiagnostics(Consumer<DiagnosticsChecker> checker, FailingRunner runner)
+ throws CompilationFailedException {
+ DiagnosticsChecker handler = new DiagnosticsChecker();
+ runner.run(handler);
+ checker.accept(handler);
+ }
+
public static void checkWarningsContains(String snippet, FailingRunner runner)
throws CompilationFailedException {
DiagnosticsChecker handler = new DiagnosticsChecker();
@@ -75,6 +99,13 @@
checkContains(snippet, handler.warnings);
}
+ public static void checkInfosContains(String snippet, FailingRunner runner)
+ throws CompilationFailedException {
+ DiagnosticsChecker handler = new DiagnosticsChecker();
+ runner.run(handler);
+ checkContains(snippet, handler.infos);
+ }
+
public static Diagnostic checkDiagnostic(Diagnostic diagnostic, Consumer<Origin> originChecker,
int lineStart, int columnStart, String... messageParts) {
if (originChecker != null) {
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index c83cd38..978c382 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -36,7 +36,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class L8CommandTest extends TestBase {
+public class L8CommandTest extends CommandTestBase<L8Command> {
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -435,12 +435,18 @@
numThreadsOptionInvalid("two");
}
- private L8Command parse(String... args) throws CompilationFailedException {
+ @Override
+ String[] requiredArgsForTest() {
+ return new String[] {"--desugared-lib", ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString()};
+ }
+
+ @Override
+ L8Command parse(String... args) throws CompilationFailedException {
return L8Command.parse(args, EmbeddedOrigin.INSTANCE).build();
}
- private L8Command parse(DiagnosticsHandler handler, String... args)
- throws CompilationFailedException {
+ @Override
+ L8Command parse(DiagnosticsHandler handler, String... args) throws CompilationFailedException {
return L8Command.parse(args, EmbeddedOrigin.INSTANCE, handler).build();
}
}
diff --git a/src/test/java/com/android/tools/r8/MarkersTest.java b/src/test/java/com/android/tools/r8/MarkersTest.java
index 1fdc6ae..6e99dc4 100644
--- a/src/test/java/com/android/tools/r8/MarkersTest.java
+++ b/src/test/java/com/android/tools/r8/MarkersTest.java
@@ -87,18 +87,18 @@
markerCompilationMode(compilationMode),
markerDesugaredLibraryIdentifier("com.tools.android:desugar_jdk_libs:" + version),
markerHasChecksums(false));
- Matcher<Marker> d8Matcher =
+ Matcher<Marker> r8Matcher =
allOf(
markerTool(Tool.R8),
markerCompilationMode(compilationMode),
markerMinApi(apiLevel),
markerR8Mode("compatibility"));
- Matcher<Marker> r8Matcher =
+ Matcher<Marker> d8Matcher =
allOf(markerTool(Tool.D8), markerCompilationMode(compilationMode), markerMinApi(apiLevel));
if (shrinkDesugaredLibrary) {
- assertMarkersMatch(markers, ImmutableList.of(l8Matcher, d8Matcher));
- } else {
assertMarkersMatch(markers, ImmutableList.of(l8Matcher, r8Matcher));
+ } else {
+ assertMarkersMatch(markers, ImmutableList.of(l8Matcher, d8Matcher));
}
}
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index 27d4655..622d595 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -27,6 +27,9 @@
extends TestShrinkerBuilder<
R8Command, Builder, ProguardTestCompileResult, ProguardTestRunResult, ProguardTestBuilder> {
+ // Version of Proguard to use.
+ private final ProguardVersion version;
+
// Ordered list of injar entries.
private List<Path> injars = new ArrayList<>();
@@ -39,12 +42,14 @@
// Additional Proguard configuration files.
private List<Path> proguardConfigFiles = new ArrayList<>();
- private ProguardTestBuilder(TestState state, Builder builder, Backend backend) {
+ private ProguardTestBuilder(
+ TestState state, ProguardVersion version, Builder builder, Backend backend) {
super(state, builder, backend);
+ this.version = version;
}
- public static ProguardTestBuilder create(TestState state) {
- return new ProguardTestBuilder(state, R8Command.builder(), Backend.CF);
+ public static ProguardTestBuilder create(TestState state, ProguardVersion version) {
+ return new ProguardTestBuilder(state, version, R8Command.builder(), Backend.CF);
}
@Override
@@ -63,7 +68,7 @@
Path mapFile = proguardOutputFolder.resolve("mapping.txt");
FileUtils.writeTextFile(configFile, config);
List<String> command = new ArrayList<>();
- command.add(ToolHelper.getProguard6Script());
+ command.add(version.getProguardScript().toString());
// Without -forceprocessing Proguard just checks the creation time on the in/out jars.
command.add("-forceprocessing");
for (Path injar : injars) {
diff --git a/src/test/java/com/android/tools/r8/ProguardVersion.java b/src/test/java/com/android/tools/r8/ProguardVersion.java
new file mode 100644
index 0000000..8c9050a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ProguardVersion.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, 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;
+
+import static com.android.tools.r8.ToolHelper.isWindows;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public enum ProguardVersion {
+ V5_2_1("5.2.1"),
+ V6_0_1("6.0.1"),
+ V7_0_0("7.0.0");
+
+ private final String version;
+
+ ProguardVersion(String version) {
+ this.version = version;
+ }
+
+ public Path getProguardScript() {
+ Path scriptDirectory = Paths.get(ToolHelper.THIRD_PARTY_DIR).resolve("proguard");
+ if (this == V7_0_0) {
+ scriptDirectory = scriptDirectory.resolve("proguard-" + version);
+ } else {
+ scriptDirectory = scriptDirectory.resolve("proguard" + version);
+ }
+ if (isWindows()) {
+ return scriptDirectory.resolve("bin/proguard.bat");
+ }
+ return scriptDirectory.resolve("bin/proguard.sh");
+ }
+
+ @Override
+ public String toString() {
+ return "Proguard " + version.toString();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 149c3c3..2f94aeb 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -45,7 +45,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class R8CommandTest extends TestBase {
+public class R8CommandTest extends CommandTestBase<R8Command> {
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -820,12 +820,18 @@
numThreadsOptionInvalid("two");
}
- private R8Command parse(String... args) throws CompilationFailedException {
+ @Override
+ String[] requiredArgsForTest() {
+ return new String[0];
+ }
+
+ @Override
+ R8Command parse(String... args) throws CompilationFailedException {
return R8Command.parse(args, EmbeddedOrigin.INSTANCE).build();
}
- private R8Command parse(DiagnosticsHandler handler, String... args)
- throws CompilationFailedException {
+ @Override
+ R8Command parse(DiagnosticsHandler handler, String... args) throws CompilationFailedException {
return R8Command.parse(args, EmbeddedOrigin.INSTANCE, handler).build();
}
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index a92fefd..27c1570 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -172,8 +172,8 @@
return JvmTestBuilder.create(new TestState(temp));
}
- public static ProguardTestBuilder testForProguard(TemporaryFolder temp) {
- return ProguardTestBuilder.create(new TestState(temp));
+ public static ProguardTestBuilder testForProguard(ProguardVersion version, TemporaryFolder temp) {
+ return ProguardTestBuilder.create(new TestState(temp), version);
}
public static GenerateMainDexListTestBuilder testForMainDexListGenerator(TemporaryFolder temp) {
@@ -308,8 +308,14 @@
return DesugarTestBuilder.create(state, builders.build());
}
+ /** @deprecated use {@link #testForProguard(ProguardVersion)} instead. */
+ @Deprecated
public ProguardTestBuilder testForProguard() {
- return testForProguard(temp);
+ return testForProguard(ProguardVersion.V6_0_1);
+ }
+
+ public ProguardTestBuilder testForProguard(ProguardVersion version) {
+ return testForProguard(version, temp);
}
public GenerateMainDexListTestBuilder testForMainDexListGenerator() {
diff --git a/src/test/java/com/android/tools/r8/TestDiagnostic.java b/src/test/java/com/android/tools/r8/TestDiagnostic.java
new file mode 100644
index 0000000..b5df861
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/TestDiagnostic.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, 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;
+
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+class TestDiagnostic implements Diagnostic {
+
+ @Override
+ public Origin getOrigin() {
+ return Origin.unknown();
+ }
+
+ @Override
+ public Position getPosition() {
+ return null;
+ }
+
+ @Override
+ public String getDiagnosticMessage() {
+ return "Test diagnostic";
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 477aab1..5f674e0 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -94,6 +94,10 @@
return addKeepRules(Arrays.asList(rules));
}
+ public T addDontWarn(Class<?> clazz) {
+ return addKeepRules("-dontwarn " + clazz.getTypeName());
+ }
+
public T addKeepKotlinMetadata() {
return addKeepRules("-keep class kotlin.Metadata { *; }");
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 7e1a627..9676011 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -702,7 +702,7 @@
}
}
- public static String getProguardScript() {
+ public static String getProguard5Script() {
if (isWindows()) {
return PROGUARD + ".bat";
}
@@ -1922,17 +1922,17 @@
public static ProcessResult runProguardRaw(
Path inJar, Path outJar, Path lib, Path config, Path map) throws IOException {
- return runProguardRaw(getProguardScript(), inJar, outJar, lib, ImmutableList.of(config), map);
+ return runProguardRaw(getProguard5Script(), inJar, outJar, lib, ImmutableList.of(config), map);
}
public static ProcessResult runProguardRaw(Path inJar, Path outJar, List<Path> config, Path map)
throws IOException {
- return runProguardRaw(getProguardScript(), inJar, outJar, config, map);
+ return runProguardRaw(getProguard5Script(), inJar, outJar, config, map);
}
public static ProcessResult runProguardRaw(Path inJar, Path outJar, Path config, Path map)
throws IOException {
- return runProguardRaw(getProguardScript(), inJar, outJar, ImmutableList.of(config), map);
+ return runProguardRaw(getProguard5Script(), inJar, outJar, ImmutableList.of(config), map);
}
public static String runProguard(Path inJar, Path outJar, Path config, Path map)
@@ -1942,7 +1942,7 @@
public static String runProguard(Path inJar, Path outJar, List<Path> config, Path map)
throws IOException {
- return runProguard(getProguardScript(), inJar, outJar, config, map);
+ return runProguard(getProguard5Script(), inJar, outJar, config, map);
}
public static ProcessResult runProguard6Raw(Path inJar, Path outJar, Path config, Path map)
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
index 982fb65..4a81ae5 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
@@ -4,17 +4,14 @@
package com.android.tools.r8.classmerging.vertical;
-import static org.hamcrest.CoreMatchers.containsString;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.errors.InternalCompilerError;
-import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,21 +34,21 @@
@Test
public void test() throws Exception {
- try {
- testForR8(parameters.getBackend())
- .addInnerClasses(getClass())
- .addKeepMainRule(TestClass.class)
- .enableCoreLibraryDesugaring(parameters.getApiLevel())
- .enableNeverClassInliningAnnotations()
- .setMinApi(parameters.getApiLevel())
- .compile();
- assertTrue(parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
- } catch (CompilationFailedException e) {
- // TODO(b/170677722): Fix compilation failure.
- assertTrue(parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
- assertTrue(e.getCause() instanceof InternalCompilerError);
- assertThat(e.getCause().getMessage(), containsString("FORCE inlining on non-inlinable"));
- }
+ // Regression test for b/170677722.
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addVerticallyMergedClassesInspector(
+ inspector -> inspector.assertMergedIntoSubtype(A.class))
+ .enableCoreLibraryDesugaring(parameters.getApiLevel())
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ assertThat(inspector.clazz(A.class), not(isPresent()));
+ assertThat(inspector.clazz(B.class), isPresent());
+ });
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
index a01a59a..9b48952 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
@@ -7,7 +7,6 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
index ac48a3d..0707ab9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
@@ -4,11 +4,13 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static org.junit.Assert.assertEquals;
+
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;
@@ -55,6 +57,49 @@
}
@Test
+ public void testCustomCollectionSuperCallsD8Cf2Cf() throws Exception {
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ Path jar =
+ testForD8(Backend.CF)
+ .addInnerClasses(CustomCollectionSuperCallsTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .allowStdoutMessages()
+ .compile()
+ .writeToZip();
+ String desugaredLibraryKeepRules = "";
+ if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
+ // Collection keep rules is only implemented in the DEX writer.
+ assertEquals(0, keepRuleConsumer.get().length());
+ desugaredLibraryKeepRules = "-keep class * { *; }";
+ }
+ D8TestRunResult d8TestRunResult;
+ if (parameters.getRuntime().isDex()) {
+ d8TestRunResult =
+ testForD8()
+ .addProgramFiles(jar)
+ .setMinApi(parameters.getApiLevel())
+ .disableDesugaring()
+ .allowStdoutMessages()
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ desugaredLibraryKeepRules,
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccess();
+ assertLines2By2Correct(d8TestRunResult.getStdOut());
+ } else {
+ testForJvm()
+ .addProgramFiles(jar)
+ .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccess();
+ }
+ }
+
+ @Test
public void testCustomCollectionSuperCallsR8() throws Exception {
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
R8TestRunResult r8TestRunResult =
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
index 3df7246..0947a55 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestRunResult;
@@ -14,6 +15,7 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -70,6 +72,56 @@
assertResultCorrect(d8TestRunResult.getStdOut());
}
+ @Test
+ public void testCustomCollectionD8Cf2Cf() throws Exception {
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ // Use D8 to desugar with Java classfile output.
+ Path jar =
+ testForD8(Backend.CF)
+ .addInnerClasses(CustomCollectionTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .writeToZip();
+ if (parameters.getRuntime().isDex()) {
+ // Collection keep rules is only implemented in the DEX writer.
+ String desugaredLibraryKeepRules = keepRuleConsumer.get();
+ if (desugaredLibraryKeepRules != null) {
+ assertEquals(0, desugaredLibraryKeepRules.length());
+ desugaredLibraryKeepRules = "-keep class * { *; }";
+ }
+ D8TestRunResult d8TestRunResult =
+ testForD8()
+ .addProgramFiles(jar)
+ .setMinApi(parameters.getApiLevel())
+ .disableDesugaring()
+ .compile()
+ .assertNoMessages()
+ .inspect(
+ inspector -> {
+ this.assertCustomCollectionCallsCorrect(inspector);
+ })
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ desugaredLibraryKeepRules,
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), EXECUTOR)
+ .assertSuccess();
+ assertResultCorrect(d8TestRunResult.getStdOut());
+ } else {
+ // Build the desugared library in class file format.
+ Path desugaredLib = getDesugaredLibraryInCF(parameters, o -> {});
+
+ // Run on the JVM with desuagred library on classpath.
+ testForJvm()
+ .addProgramFiles(jar)
+ .addRunClasspathFiles(desugaredLib)
+ .run(parameters.getRuntime(), EXECUTOR)
+ .assertSuccess();
+ }
+ }
+
private void assertResultCorrect(String stdOut) {
if (requiresEmulatedInterfaceCoreLibDesugaring(parameters) && !shrinkDesugaredLibrary) {
// When shrinking the class names are not printed correctly anymore due to minification.
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
index ff0141f..a3b768d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
@@ -11,13 +11,14 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
import java.time.LocalDate;
import java.util.List;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -33,7 +34,8 @@
@Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+ BooleanUtils.values());
}
public DesugaredGenericSignatureTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
@@ -43,6 +45,7 @@
@Test
public void testD8() throws Exception {
+ Assume.assumeTrue(parameters.getRuntime().isDex());
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForD8()
.addInnerClasses(DesugaredGenericSignatureTest.class)
@@ -61,7 +64,51 @@
}
@Test
+ public void testD8Cf2Cf() throws Exception {
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+
+ Path jar =
+ testForD8(Backend.CF)
+ .addInnerClasses(DesugaredGenericSignatureTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .setIncludeClassesChecksum(true)
+ .setMinApi(parameters.getApiLevel())
+ .allowStdoutMessages()
+ .compile()
+ .writeToZip();
+ String desugaredLibraryKeepRules = "";
+ if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
+ // Collection keep rules is only implemented in the DEX writer.
+ assertEquals(0, keepRuleConsumer.get().length());
+ desugaredLibraryKeepRules = "-keep class * { *; }";
+ }
+ if (parameters.getRuntime().isDex()) {
+ testForD8()
+ .addProgramFiles(jar)
+ .setMinApi(parameters.getApiLevel())
+ .disableDesugaring()
+ .allowStdoutMessages()
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ desugaredLibraryKeepRules,
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED);
+ } else {
+ testForJvm()
+ .addProgramFiles(jar)
+ .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+ }
+
+ @Test
public void testR8() throws Exception {
+ Assume.assumeTrue(parameters.getRuntime().isDex());
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(parameters.getBackend())
.addInnerClasses(DesugaredGenericSignatureTest.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index e4b3869..b02b2e9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -119,7 +119,6 @@
options -> {
if (extraFiles) {
options.testing.disableL8AnnotationRemoval = true;
- options.testing.forceLibBackportsInL8CfToCf = true;
}
optionsModifier.accept(options);
});
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index 346743b..b726614 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -93,32 +93,28 @@
.parse(StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
- if (apiLevel == AndroidApiLevel.R) {
- // Skip API level 30 for now.
+ Path compileApiLevelDirectory = directory.resolve("compile_api_level_" + apiLevel.getLevel());
+ if (apiLevel.getLevel()
+ < desugaredLibraryConfiguration.getRequiredCompilationApiLevel().getLevel()) {
+ System.out.println("!Checking " + compileApiLevelDirectory);
continue;
}
-
- if (apiLevel.getLevel()
- >= desugaredLibraryConfiguration.getRequiredCompilationApiLevel().getLevel()) {
- Path compileApiLevelDirectory =
- directory.resolve("compile_api_level_" + apiLevel.getLevel());
- assertTrue(Files.exists(compileApiLevelDirectory));
- for (AndroidApiLevel minApiLevel : AndroidApiLevel.values()) {
- String desugaredApisBaseName =
- "desugared_apis_" + apiLevel.getLevel() + "_" + minApiLevel.getLevel();
- if (minApiLevel == AndroidApiLevel.L || minApiLevel == AndroidApiLevel.B) {
- assertTrue(
- Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt")));
- assertTrue(
- Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".jar")));
- checkFileContent(
- minApiLevel, compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt"));
- } else {
- assertFalse(
- Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt")));
- assertFalse(
- Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".jar")));
- }
+ assertTrue(Files.exists(compileApiLevelDirectory));
+ for (AndroidApiLevel minApiLevel : AndroidApiLevel.values()) {
+ String desugaredApisBaseName =
+ "desugared_apis_" + apiLevel.getLevel() + "_" + minApiLevel.getLevel();
+ if (minApiLevel == AndroidApiLevel.L || minApiLevel == AndroidApiLevel.B) {
+ assertTrue(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt")));
+ assertTrue(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".jar")));
+ checkFileContent(
+ minApiLevel, compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt"));
+ } else {
+ assertFalse(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt")));
+ assertFalse(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".jar")));
}
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
index c663489..c9b2a93 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
@@ -4,10 +4,12 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static org.junit.Assert.assertEquals;
+
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
import java.time.chrono.Chronology;
import java.util.List;
import java.util.Map;
@@ -28,7 +30,8 @@
@Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+ BooleanUtils.values());
}
public StaticInterfaceMethodTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
@@ -61,6 +64,45 @@
}
@Test
+ public void testStaticInterfaceMethodsD8CfToCf() throws Exception {
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ Path jar =
+ testForD8(Backend.CF)
+ .addInnerClasses(StaticInterfaceMethodTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .writeToZip();
+
+ String desugaredLibraryKeepRules = "";
+ if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
+ // Collection keep rules is only implemented in the DEX writer.
+ assertEquals(0, keepRuleConsumer.get().length());
+ desugaredLibraryKeepRules = "-keep class * { *; }";
+ }
+ if (parameters.getRuntime().isDex()) {
+ testForD8()
+ .addProgramFiles(jar)
+ .setMinApi(parameters.getApiLevel())
+ .disableDesugaring()
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ desugaredLibraryKeepRules,
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ } else {
+ testForJvm()
+ .addProgramFiles(jar)
+ .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+ }
+
+ @Test
public void testStaticInterfaceMethodsR8() throws Exception {
// Desugared library tests do not make sense in the Cf to Cf, and the JVM is already tested
// in the D8 test. Just return.
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java
index e8aa581..6afc3a5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
+import static org.junit.Assert.assertEquals;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -80,6 +82,52 @@
}
@Test
+ public void testFunctionCompositionD8Cf2Cf() throws Exception {
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ Path jar =
+ testForD8(Backend.CF)
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(
+ Executor.class,
+ Executor.Object1.class,
+ Executor.Object2.class,
+ Executor.Object3.class)
+ .addLibraryClasses(CustomLibClass.class)
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .writeToZip();
+ String desugaredLibraryKeepRules = "";
+ if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
+ // Collection keep rules is only implemented in the DEX writer.
+ assertEquals(0, keepRuleConsumer.get().length());
+ desugaredLibraryKeepRules = "-keep class * { *; }";
+ }
+ if (parameters.getRuntime().isDex()) {
+ testForD8()
+ .addProgramFiles(jar)
+ .setMinApi(parameters.getApiLevel())
+ .disableDesugaring()
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ desugaredLibraryKeepRules,
+ shrinkDesugaredLibrary)
+ .addRunClasspathFiles(CUSTOM_LIB)
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+
+ } else {
+ testForJvm()
+ .addProgramFiles(jar)
+ .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
+ .addRunClasspathFiles(CUSTOM_LIB)
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+ }
+
+ @Test
public void testFunctionCompositionR8() throws Exception {
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
index 9d9b5cb..394f36c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -37,23 +38,27 @@
@RunWith(Parameterized.class)
public class Jdk11StreamTests extends Jdk11DesugaredLibraryTestBase {
+ private final boolean useCf2Cf;
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{2}, shrinkDesugaredLibrary: {0}, useCf2Cf: {1}")
public static List<Object[]> data() {
// TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required and
// present only in ART runtimes.
return buildParameters(
BooleanUtils.values(),
+ BooleanUtils.values(),
getTestParameters()
.withDexRuntimesStartingFromIncluding(Version.V5_1_1)
.withAllApiLevels()
.build());
}
- public Jdk11StreamTests(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ public Jdk11StreamTests(
+ boolean shrinkDesugaredLibrary, boolean useCf2Cf, TestParameters parameters) {
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.useCf2Cf = useCf2Cf;
this.parameters = parameters;
}
@@ -188,34 +193,71 @@
"Requires Java base extensions, should add it when not desugaring",
parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel());
- D8TestCompileResult compileResult = compileStreamTestsToDex();
+ D8TestCompileResult compileResult = compileStreamTestsToDex(useCf2Cf);
runSuccessfulTests(compileResult);
runFailingTests(compileResult);
}
- private D8TestCompileResult compileStreamTestsToDex() throws Exception {
+ private D8TestCompileResult compileStreamTestsToDex(boolean cf2cf) throws Exception {
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
List<Path> filesToCompile =
Arrays.stream(JDK_11_STREAM_TEST_COMPILED_FILES)
.filter(file -> !file.toString().contains("lang/invoke"))
.collect(Collectors.toList());
- return testForD8()
- .addProgramFiles(filesToCompile)
- .addProgramFiles(getPathsFiles())
- .addProgramFiles(getSafeVarArgsFile())
- .addProgramFiles(testNGSupportProgramFiles())
- .addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibraryWithJavaBaseExtension,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .withArtFrameworks()
- .withArt6Plus64BitsLib();
+
+ if (cf2cf) {
+ Path jar =
+ testForD8(Backend.CF)
+ .addProgramFiles(filesToCompile)
+ .addProgramFiles(getPathsFiles())
+ .addProgramFiles(getSafeVarArgsFile())
+ .addProgramFiles(testNGSupportProgramFiles())
+ .addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .allowStdoutMessages()
+ .compile()
+ .writeToZip();
+ // Collection keep rules is only implemented in the DEX writer.
+ String desugaredLibraryKeepRules = keepRuleConsumer.get();
+ if (desugaredLibraryKeepRules != null) {
+ assertEquals(0, desugaredLibraryKeepRules.length());
+ desugaredLibraryKeepRules = "-keep class * { *; }";
+ }
+ return testForD8()
+ .addProgramFiles(jar)
+ .setMinApi(parameters.getApiLevel())
+ .disableDesugaring()
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibraryWithJavaBaseExtension,
+ parameters.getApiLevel(),
+ desugaredLibraryKeepRules,
+ shrinkDesugaredLibrary)
+ .withArtFrameworks()
+ .withArt6Plus64BitsLib();
+
+ } else {
+
+ return testForD8()
+ .addProgramFiles(filesToCompile)
+ .addProgramFiles(getPathsFiles())
+ .addProgramFiles(getSafeVarArgsFile())
+ .addProgramFiles(testNGSupportProgramFiles())
+ .addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibraryWithJavaBaseExtension,
+ parameters.getApiLevel(),
+ keepRuleConsumer.get(),
+ shrinkDesugaredLibrary)
+ .withArtFrameworks()
+ .withArt6Plus64BitsLib();
+ }
}
private void runSuccessfulTests(D8TestCompileResult compileResult) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/SingletonCanonicalizationWithApiLevelCheckTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/SingletonCanonicalizationWithApiLevelCheckTest.java
new file mode 100644
index 0000000..7f5b905
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/SingletonCanonicalizationWithApiLevelCheckTest.java
@@ -0,0 +1,120 @@
+// Copyright (c) 2020, 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.ir.optimize.canonicalization;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.google.common.collect.ImmutableList;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.util.List;
+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 SingletonCanonicalizationWithApiLevelCheckTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public SingletonCanonicalizationWithApiLevelCheckTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ Path program =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class, Companion.class, A.class)
+ .addLibraryClasses(LibraryVersion.class, LibraryInterfaceAddedInApi1.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+
+ // Run with library version 1 that includes LibraryInterfaceAddedInApi1.
+ testForR8(parameters.getBackend())
+ .addProgramClasses(LibraryVersion.class, LibraryInterfaceAddedInApi1.class)
+ .addKeepAllClassesRule()
+ .addKeepRules(getAssumeValuesRule(1))
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .addRunClasspathFiles(program)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("A");
+
+ // Run with library version 0 that does not include LibraryInterfaceAddedInApi1.
+ testForR8(parameters.getBackend())
+ .addProgramClasses(LibraryVersion.class)
+ .addKeepAllClassesRule()
+ .addKeepRules(getAssumeValuesRule(0))
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .addRunClasspathFiles(program)
+ .run(parameters.getRuntime(), TestClass.class)
+ .apply(
+ runResult -> {
+ if (parameters.isCfRuntime()) {
+ // Constant canonicalization is disabled for CF.
+ runResult.assertSuccessWithEmptyOutput();
+ } else {
+ runResult.assertFailureWithErrorThatThrows(NoClassDefFoundError.class);
+ }
+ });
+ }
+
+ private List<String> getAssumeValuesRule(int version) {
+ return ImmutableList.of(
+ "-assumevalues class " + LibraryVersion.class.getTypeName() + " {",
+ " static int init() return " + version + ";",
+ "}");
+ }
+
+ public static class LibraryVersion {
+
+ public static int SDK_INT = init();
+
+ private static int init() {
+ return 0;
+ }
+ }
+
+ public interface LibraryInterfaceAddedInApi1 {}
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ if (LibraryVersion.SDK_INT >= 1) {
+ PrintStream out = System.out;
+ if (System.currentTimeMillis() > 0) {
+ out.println(Companion.INSTANCE);
+ } else {
+ out.print(Companion.INSTANCE);
+ }
+ }
+ }
+ }
+
+ static class Companion {
+
+ static A INSTANCE = new A();
+ }
+
+ static class A implements LibraryInterfaceAddedInApi1 {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
index 95fef57..415a868 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
@@ -5,13 +5,12 @@
package com.android.tools.r8.ir.optimize.inliner;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,14 +40,10 @@
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(
- inspector -> {
- // TODO(b/171197204): Method should be inlined.
- assertThat(
- inspector.clazz(TestClass.class).uniqueMethodWithName("test"),
- notIf(
- isPresent(),
- parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)));
- });
+ inspector ->
+ assertThat(
+ inspector.clazz(TestClass.class).uniqueMethodWithName("test"),
+ not(isPresent())));
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/LibraryMemberRebindingTest.java b/src/test/java/com/android/tools/r8/memberrebinding/LibraryMemberRebindingTest.java
new file mode 100644
index 0000000..ed90756
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/LibraryMemberRebindingTest.java
@@ -0,0 +1,123 @@
+// Copyright (c) 2020, 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 com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.nio.file.Path;
+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 LibraryMemberRebindingTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public LibraryMemberRebindingTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testWithEmptyA() throws Exception {
+ Path compileTimeLibrary = compileLibraryForAppCompilation(LibraryB.class, LibraryA.class);
+ test(compileTimeLibrary, compileTimeLibrary);
+ }
+
+ @Test
+ public void testWithEmptyB() throws Exception {
+ Path compileTimeLibrary = compileLibraryForAppCompilation(LibraryA.class, LibraryB.class);
+ test(compileTimeLibrary, compileTimeLibrary);
+ }
+
+ @Test
+ public void testWithEmptyBOnlyAtCompileTime() throws Exception {
+ Path compileTimeLibrary = compileLibraryForAppCompilation(LibraryA.class, LibraryB.class);
+ Path runtimeLibrary = compileLibraryForAppCompilation(LibraryB.class, LibraryA.class);
+ test(compileTimeLibrary, runtimeLibrary);
+ }
+
+ private void test(Path compileTimeLibrary, Path runtimeLibrary) throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .addLibraryFiles(compileTimeLibrary)
+ .addDefaultRuntimeLibrary(parameters)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .apply(compileResult -> configureRunClasspath(compileResult, runtimeLibrary))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("42");
+ }
+
+ private Path compileLibraryForAppCompilation(
+ Class<?> nonEmptyLibraryClass, Class<?> emptyLibraryClass) throws Exception {
+ return testForR8(Backend.CF)
+ .addProgramClasses(nonEmptyLibraryClass)
+ .addProgramClassFileData(
+ transformer(emptyLibraryClass)
+ .removeFields(
+ (int access, String name, String descriptor, String signature, Object value) ->
+ true)
+ .removeMethods(
+ (int access,
+ String name,
+ String descriptor,
+ String signature,
+ String[] exceptions) -> !name.equals("<init>"))
+ .transform())
+ .addKeepAllClassesRule()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+ }
+
+ private void configureRunClasspath(R8TestCompileResult compileResult, Path library)
+ throws Exception {
+ if (parameters.isCfRuntime()) {
+ compileResult.addRunClasspathFiles(library);
+ } else {
+ compileResult.addRunClasspathFiles(
+ testForD8()
+ .addProgramFiles(library)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip());
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println(LibraryB.f + LibraryB.m());
+ }
+ }
+
+ static class LibraryA {
+
+ public static int f = 21;
+
+ public static int m() {
+ return 21;
+ }
+ }
+
+ static class LibraryB extends LibraryA {
+
+ public static int f = 21;
+
+ public static int m() {
+ return 21;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/proguard/AllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/proguard/AllowShrinkingCompatibilityTest.java
new file mode 100644
index 0000000..ca30a1f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/proguard/AllowShrinkingCompatibilityTest.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2020, 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.proguard;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.ProguardVersion;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.util.List;
+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 AllowShrinkingCompatibilityTest extends TestBase {
+
+ private final boolean allowOptimization;
+ private final TestParameters parameters;
+ private final ProguardVersion proguardVersion;
+
+ @Parameters(name = "{1}, {2}, allow optimization: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(),
+ getTestParameters().withCfRuntimes().build(),
+ ProguardVersion.values());
+ }
+
+ public AllowShrinkingCompatibilityTest(
+ boolean allowOptimization, TestParameters parameters, ProguardVersion proguardVersion) {
+ this.allowOptimization = allowOptimization;
+ this.parameters = parameters;
+ this.proguardVersion = proguardVersion;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForProguard(proguardVersion)
+ .addProgramClasses(TestClass.class, Companion.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(
+ "-keep,allowshrinking"
+ + (allowOptimization ? ",allowoptimization" : "")
+ + " class "
+ + Companion.class.getTypeName()
+ + " { <methods>; }")
+ .addDontWarn(getClass())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject testClassSubject = inspector.clazz(TestClass.class);
+ assertThat(testClassSubject, isPresent());
+
+ ClassSubject companionClassSubject = inspector.clazz(Companion.class);
+ assertThat(companionClassSubject, notIf(isPresent(), allowOptimization));
+
+ MethodSubject mainMethodSubject = testClassSubject.mainMethod();
+ MethodSubject getMethodSubject = companionClassSubject.uniqueMethodWithName("get");
+
+ if (allowOptimization) {
+ assertTrue(
+ testClassSubject
+ .mainMethod()
+ .streamInstructions()
+ .allMatch(InstructionSubject::isReturnVoid));
+ } else {
+ assertThat(mainMethodSubject, invokesMethod(getMethodSubject));
+ assertThat(getMethodSubject, isPresent());
+ }
+ })
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithEmptyOutput();
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ if (Companion.get() != 42) {
+ System.out.println("Hello world!");
+ }
+ }
+ }
+
+ static class Companion {
+
+ static int get() {
+ return 42;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceFieldTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceFieldTests.java
index 3a6ffe6..2b90ffc 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceFieldTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceFieldTests.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.retrace;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
+import com.android.tools.r8.retrace.internal.RetracerImpl;
import com.android.tools.r8.retrace.mappings.FieldsWithSameMinifiedNameMapping;
import com.android.tools.r8.retrace.mappings.MappingForTest;
import java.util.function.Consumer;
@@ -13,13 +14,13 @@
public class RetraceFieldTests {
@Test
- public void testFieldsWithSameMinifiedName() throws Exception {
+ public void testFieldsWithSameMinifiedName() {
FieldsWithSameMinifiedNameMapping mapping = new FieldsWithSameMinifiedNameMapping();
runRetraceTest(mapping, mapping::inspect);
}
- private void runRetraceTest(MappingForTest mappingForTest, Consumer<RetraceApi> inspection)
- throws Exception {
- inspection.accept(Retracer.create(mappingForTest::mapping, new TestDiagnosticMessagesImpl()));
+ private void runRetraceTest(MappingForTest mappingForTest, Consumer<Retracer> inspection) {
+ inspection.accept(
+ RetracerImpl.create(mappingForTest::mapping, new TestDiagnosticMessagesImpl()));
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
index 4fb8389..b8b1647 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
@@ -440,7 +440,7 @@
@Override
public List<String> retracedStackTrace() {
- return ImmutableList.of("com.android.tools.r8.R8.a(42)");
+ return ImmutableList.of("com.android.tools.r8.R8.foo(42)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index 1b6735f..edcb118 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -15,7 +15,8 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.retrace.Retrace.RetraceAbortException;
+import com.android.tools.r8.retrace.internal.RetraceAbortException;
+import com.android.tools.r8.retrace.internal.RetracerImpl;
import com.android.tools.r8.retrace.stacktraces.ActualBotStackTraceBase;
import com.android.tools.r8.retrace.stacktraces.ActualIdentityStackTrace;
import com.android.tools.r8.retrace.stacktraces.ActualRetraceBotStackTrace;
@@ -26,6 +27,7 @@
import com.android.tools.r8.retrace.stacktraces.CircularReferenceStackTrace;
import com.android.tools.r8.retrace.stacktraces.FileNameExtensionStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineFileNameStackTrace;
+import com.android.tools.r8.retrace.stacktraces.InlineFileNameWithInnerClassesStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineNoLineNumberStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineSourceFileContextStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineWithLineNumbersStackTrace;
@@ -85,6 +87,11 @@
}
@Test
+ public void testInlineFileNameWithInnerClassesStackTrace() {
+ runRetraceTest(new InlineFileNameWithInnerClassesStackTrace());
+ }
+
+ @Test
public void testNullLineTrace() {
TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
NullStackTrace nullStackTrace = new NullStackTrace();
@@ -201,9 +208,9 @@
}
private void inspectRetraceTest(
- StackTraceForTest stackTraceForTest, Consumer<RetraceApi> inspection) throws Exception {
+ StackTraceForTest stackTraceForTest, Consumer<Retracer> inspection) throws Exception {
inspection.accept(
- Retracer.create(stackTraceForTest::mapping, new TestDiagnosticMessagesImpl()));
+ RetracerImpl.create(stackTraceForTest::mapping, new TestDiagnosticMessagesImpl()));
}
private TestDiagnosticMessagesImpl runRetraceTest(StackTraceForTest stackTraceForTest) {
diff --git a/src/test/java/com/android/tools/r8/retrace/mappings/FieldsWithSameMinifiedNameMapping.java b/src/test/java/com/android/tools/r8/retrace/mappings/FieldsWithSameMinifiedNameMapping.java
index 488a00a..fa9ca5f 100644
--- a/src/test/java/com/android/tools/r8/retrace/mappings/FieldsWithSameMinifiedNameMapping.java
+++ b/src/test/java/com/android/tools/r8/retrace/mappings/FieldsWithSameMinifiedNameMapping.java
@@ -9,8 +9,8 @@
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.retrace.RetraceApi;
import com.android.tools.r8.retrace.RetraceFieldResult;
+import com.android.tools.r8.retrace.Retracer;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -25,7 +25,7 @@
"foo.bar.Baz -> foo.bar.Baz:", " java.lang.Object f1 -> a", " java.lang.String f2 -> a");
}
- public void inspect(RetraceApi retracer) {
+ public void inspect(Retracer retracer) {
FieldReference f1FieldReference =
Reference.field(
Reference.classFromTypeName("foo.bar.Baz"),
@@ -43,7 +43,7 @@
"a",
Reference.classFromTypeName("java.lang.Object"));
- RetraceFieldResult result = retracer.retrace(mappedF1FieldReference);
+ RetraceFieldResult result = retracer.retraceField(mappedF1FieldReference);
// TODO(b/169829306): Result should not be ambigious.
assertTrue(result.isAmbiguous());
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineFileNameWithInnerClassesStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineFileNameWithInnerClassesStackTrace.java
new file mode 100644
index 0000000..20ed6ec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineFileNameWithInnerClassesStackTrace.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class InlineFileNameWithInnerClassesStackTrace implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.main(Main.dummy:3)");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat foo.Bar$Baz$Qux.baz(Bar.dummy:0)",
+ "\tat com.android.tools.r8.naming.retrace.Main.main(Main.dummy:7)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "com.android.tools.r8.naming.retrace.Main -> com.android.tools.r8.naming.retrace.Main:",
+ " 3:3:void foo.Bar$Baz$Qux.baz(long):0:0 -> main",
+ " 3:3:void main(java.lang.String[]):7 -> main");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/MemberFieldOverlapStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/MemberFieldOverlapStackTrace.java
index 3ca3297..080990f 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/MemberFieldOverlapStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/MemberFieldOverlapStackTrace.java
@@ -9,9 +9,9 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.retrace.RetraceApi;
import com.android.tools.r8.retrace.RetraceFieldResult;
import com.android.tools.r8.retrace.RetraceFieldResult.Element;
+import com.android.tools.r8.retrace.Retracer;
import com.android.tools.r8.utils.StringUtils;
import java.util.Arrays;
import java.util.List;
@@ -42,12 +42,12 @@
return 1;
}
- public void inspectField(RetraceApi retracer) {
+ public void inspectField(Retracer retracer) {
RetraceFieldResult result =
- retracer.retrace(Reference.classFromTypeName("a.A")).lookupField("a");
+ retracer.retraceClass(Reference.classFromTypeName("a.A")).lookupField("a");
assertFalse(result.isAmbiguous());
assertEquals(1, result.stream().count());
- Optional<Element> field = result.stream().findFirst();
+ Optional<? extends Element> field = result.stream().findFirst();
assertTrue(field.isPresent());
assertEquals("field", field.get().getField().getFieldName());
}
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 222c6a8..c15fb48 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -3175,4 +3175,33 @@
}
});
}
+
+ @Test
+ public void parseKeepXNamesIsAllowShrinking() {
+ for (String rule : ImmutableList.of("-keep", "-keepclassmembers", "-keepclasseswithmembers")) {
+ for (String modifier :
+ ImmutableList.of("", "names", ",allowshrinking", "names,allowshrinking")) {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(dexItemFactory, reporter);
+ String ruleWithModifier =
+ (rule.endsWith("s") && (!modifier.startsWith(",") && !modifier.isEmpty())
+ ? rule.substring(0, rule.length() - 1)
+ : rule)
+ + modifier;
+ parser.parse(
+ createConfigurationForTesting(ImmutableList.of(ruleWithModifier + " class A")));
+ verifyParserEndsCleanly();
+
+ ProguardConfiguration configuration = parser.getConfig();
+ assertEquals(1, configuration.getRules().size());
+ assertEquals(
+ !modifier.isEmpty(),
+ ListUtils.first(configuration.getRules())
+ .asProguardKeepRule()
+ .getModifiers()
+ .allowsShrinking);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/shaking/attributes/KeepEnclosingMethodForKeptMethodTest.java b/src/test/java/com/android/tools/r8/shaking/attributes/KeepEnclosingMethodForKeptMethodTest.java
new file mode 100644
index 0000000..cc1f241
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/attributes/KeepEnclosingMethodForKeptMethodTest.java
@@ -0,0 +1,129 @@
+// Copyright (c) 2020, 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.attributes;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+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 KeepEnclosingMethodForKeptMethodTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final String[] EXPECTED = {
+ "null",
+ "class com.android.tools.r8.shaking.attributes.KeepEnclosingMethodForKeptMethodTest"
+ + "$KeptClass",
+ "public static com.android.tools.r8.shaking.attributes.KeepEnclosingMethodForKeptMethodTest$I "
+ + "com.android.tools.r8.shaking.attributes.KeepEnclosingMethodForKeptMethodTest$KeptClass.enclosingFromKeptMethod()",
+ "public"
+ + " com.android.tools.r8.shaking.attributes.KeepEnclosingMethodForKeptMethodTest$KeptClass()"
+ };
+ private final String[] R8_OUTPUT = {
+ "null",
+ "class com.android.tools.r8.shaking.attributes.KeepEnclosingMethodForKeptMethodTest"
+ + "$KeptClass",
+ "null",
+ "null"
+ };
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public KeepEnclosingMethodForKeptMethodTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addInnerClasses(KeptClass.class)
+ .addProgramClassFileData(
+ transformer(I.class).removeInnerClasses().transform(),
+ transformer(KeptClass.class).removeInnerClasses().transform())
+ .run(parameters.getRuntime(), KeptClass.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8Full() throws Exception {
+ // TODO(b/171194649): This should output EXPECTED.
+ runTest(testForR8(parameters.getBackend())).assertSuccessWithOutputLines(R8_OUTPUT);
+ }
+
+ @Test
+ public void testR8Compat() throws Exception {
+ runTest(testForR8Compat(parameters.getBackend())).assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ private R8TestRunResult runTest(R8TestBuilder<?> testBuilder) throws Exception {
+ return testBuilder
+ .addInnerClasses(KeptClass.class)
+ .addProgramClassFileData(
+ transformer(I.class).removeInnerClasses().transform(),
+ transformer(KeptClass.class).removeInnerClasses().transform())
+ .addKeepClassRules(I.class)
+ .addKeepAttributeInnerClassesAndEnclosingMethod()
+ .addKeepMainRule(KeptClass.class)
+ .addKeepClassAndMembersRules(KeptClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableInliningAnnotations()
+ .run(parameters.getRuntime(), KeptClass.class);
+ }
+
+ public interface I {
+
+ void foo();
+ }
+
+ public static class KeptClass {
+
+ static I staticField =
+ new I() {
+ @Override
+ public void foo() {
+ System.out.println(this.getClass().getEnclosingConstructor());
+ System.out.println(this.getClass().getEnclosingClass());
+ }
+ };
+
+ private I instanceField;
+
+ public KeptClass() {
+ instanceField =
+ new I() {
+ @Override
+ public void foo() {
+ System.out.println(this.getClass().getEnclosingConstructor());
+ }
+ };
+ }
+
+ public static void main(String[] args) {
+ staticField.foo();
+ enclosingFromKeptMethod().foo();
+ new KeptClass().instanceField.foo();
+ }
+
+ @NeverInline
+ public static I enclosingFromKeptMethod() {
+ return new I() {
+ @Override
+ public void foo() {
+ System.out.println(this.getClass().getEnclosingMethod());
+ }
+ };
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 1772e48..d2518b6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -34,9 +34,9 @@
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.retrace.DirectClassNameMapperProguardMapProducer;
-import com.android.tools.r8.retrace.RetraceApi;
import com.android.tools.r8.retrace.Retracer;
+import com.android.tools.r8.retrace.internal.DirectClassNameMapperProguardMapProducer;
+import com.android.tools.r8.retrace.internal.RetracerImpl;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.BiMapContainer;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -463,8 +463,8 @@
}
}
- public RetraceApi retrace() {
- return Retracer.create(
+ public Retracer retrace() {
+ return RetracerImpl.create(
new InternalProguardMapProducer(
mapping == null ? ClassNameMapper.builder().build() : mapping),
new TestDiagnosticMessagesImpl());
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index bcedc29..d8aa792 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -31,9 +31,9 @@
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.retrace.RetraceApi;
import com.android.tools.r8.retrace.RetraceTypeResult;
import com.android.tools.r8.retrace.RetracedField;
+import com.android.tools.r8.retrace.Retracer;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ZipUtils;
@@ -223,7 +223,7 @@
// TODO(b/169882658): This should be removed when we have identity mappings for ambiguous cases.
public FieldSubject uniqueFieldWithName(String name, TypeReference originalType) {
- RetraceApi retracer = codeInspector.retrace();
+ Retracer retracer = codeInspector.retrace();
Set<FoundFieldSubject> candidates = Sets.newIdentityHashSet();
Set<FoundFieldSubject> sameTypeCandidates = Sets.newIdentityHashSet();
for (FoundFieldSubject candidate : allFields()) {
@@ -236,7 +236,7 @@
}
}
retracer
- .retrace(fieldReference)
+ .retraceField(fieldReference)
.forEach(
element -> {
RetracedField field = element.getField();
@@ -246,7 +246,7 @@
TypeReference fieldOriginalType = originalType;
if (fieldOriginalType == null) {
RetraceTypeResult retraceTypeResult =
- retracer.retrace(fieldReference.getFieldType());
+ retracer.retraceType(fieldReference.getFieldType());
assert !retraceTypeResult.isAmbiguous();
fieldOriginalType =
retraceTypeResult.stream().iterator().next().getType().getTypeReference();
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 6f6bbf8..e6e26fd 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
@@ -6,9 +6,9 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.retrace.RetraceApi;
import com.android.tools.r8.retrace.RetraceFrameResult;
import com.android.tools.r8.retrace.RetraceMethodResult;
+import com.android.tools.r8.retrace.Retracer;
public interface InstructionSubject {
@@ -132,17 +132,17 @@
return lineNumberTable == null ? -1 : lineNumberTable.getLineForInstruction(this);
}
- default RetraceMethodResult retrace(RetraceApi retracer) {
+ default RetraceMethodResult retrace(Retracer retracer) {
MethodSubject methodSubject = getMethodSubject();
assert methodSubject.isPresent();
- return retracer.retrace(methodSubject.asFoundMethodSubject().asMethodReference());
+ return retracer.retraceMethod(methodSubject.asFoundMethodSubject().asMethodReference());
}
- default RetraceFrameResult retraceLinePosition(RetraceApi retracer) {
+ default RetraceFrameResult retraceLinePosition(Retracer retracer) {
return retrace(retracer).narrowByPosition(getLineNumber());
}
- default RetraceFrameResult retracePcPosition(RetraceApi retracer, MethodSubject methodSubject) {
+ default RetraceFrameResult retracePcPosition(Retracer retracer, MethodSubject methodSubject) {
return retrace(retracer).narrowByPosition(getOffset(methodSubject).offset);
}
}