Merge commit '5182c2d1499a93910b0735ba5360ead042013aea' into dev-release
diff --git a/AUTHORS b/AUTHORS
index 02ac16e..df9cd8d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -5,6 +5,7 @@
Google Inc.
Uber Technologies Inc.
+Square Inc.
Albert Jin <albert.jin@gmail.com>
Kevin Sun <snxngxng@gmail.com>
diff --git a/build.gradle b/build.gradle
index 2e908a5..30c839c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -307,6 +307,7 @@
"android_jar/lib-v28",
"android_jar/lib-v29",
"android_jar/lib-v30",
+ "android_jar/lib-v31",
"core-lambda-stubs",
"dart-sdk",
"ddmlib",
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index cdbcdd8..9b3f92c 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -27,8 +27,10 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
+import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.PrefixRewritingNamingLens;
+import com.android.tools.r8.naming.ProguardMapSupplier;
import com.android.tools.r8.naming.RecordRewritingNamingLens;
import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
import com.android.tools.r8.origin.CommandLineOrigin;
@@ -41,6 +43,8 @@
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
+import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
+import com.android.tools.r8.utils.LineNumberOptimizer;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThreadUtils;
@@ -268,9 +272,10 @@
namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
}
if (options.isGeneratingClassFiles()) {
- // TODO(b/158159959): Move this out so it is shared for both CF and DEX pipelines.
- SyntheticFinalization.finalize(appView);
- new CfApplicationWriter(appView, marker, GraphLens.getIdentityLens(), namingLens, null)
+ ProguardMapSupplier proguardMapSupplier =
+ finalizeApplication(inputApp, appView, namingLens);
+ new CfApplicationWriter(
+ appView, marker, GraphLens.getIdentityLens(), namingLens, proguardMapSupplier)
.write(options.getClassFileConsumer());
} else {
if (!hasDexResources || !hasClassResources || !appView.rewritePrefix.isRewriting()) {
@@ -311,9 +316,8 @@
executor, appView.appInfo().app(), appView.appInfo().getMainDexInfo());
appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(mainDexInfo));
}
-
- // TODO(b/158159959): Move this out so it is shared for both CF and DEX pipelines.
- SyntheticFinalization.finalize(appView);
+ ProguardMapSupplier proguardMapSupplier =
+ finalizeApplication(inputApp, appView, namingLens);
new ApplicationWriter(
appView,
@@ -321,7 +325,7 @@
appView.graphLens(),
InitClassLens.getDefault(),
namingLens,
- null)
+ proguardMapSupplier)
.write(executor);
}
options.printWarnings();
@@ -336,6 +340,19 @@
}
}
+ private static ProguardMapSupplier finalizeApplication(
+ AndroidApp inputApp, AppView<AppInfo> appView, NamingLens namingLens) {
+ SyntheticFinalization.finalize(appView);
+ // TODO(b/37830524): Once D8 supports PC mapping this will need to be run for that too.
+ assert appView.options().lineNumberOptimization == LineNumberOptimization.OFF;
+ if (appView.options().proguardMapConsumer == null) {
+ return null;
+ }
+ ClassNameMapper classNameMapper =
+ LineNumberOptimizer.run(appView, appView.appInfo().app(), inputApp, namingLens);
+ return ProguardMapSupplier.create(classNameMapper, appView.options());
+ }
+
private static DexApplication rewriteNonDexInputs(
AppView<AppInfo> appView,
AndroidApp inputApp,
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 05c2e8e..7e20368 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
+import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
@@ -459,6 +460,7 @@
internal.readCompileTimeAnnotations = intermediate;
internal.desugarGraphConsumer = desugarGraphConsumer;
internal.mainDexKeepRules = mainDexKeepRules;
+ internal.lineNumberOptimization = LineNumberOptimization.OFF;
// Assert and fixup defaults.
assert !internal.isShrinking();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index e6bc084..3fb79c6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -2211,6 +2211,14 @@
TypeElement.fromDexType(phiTypeForBlock, Nullability.maybeNull(), appView),
local,
readType);
+ } else if (readType == RegisterReadType.DEBUG) {
+ throw new InvalidDebugInfoException(
+ "Information in locals-table is invalid with respect to the stack map table. "
+ + "Local refers to non-present stack map type for register: "
+ + register
+ + " with constraint "
+ + constraint
+ + ".");
} else {
assert method.getDefinition().getClassFileVersion().isLessThan(CfVersion.V1_8);
hasIncorrectStackMapTypes = true;
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 2fc5c3a..8c7528c 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
@@ -983,6 +983,17 @@
new MethodGenerator(
method, BackportedMethods::CollectionsMethods_copyOfSet, "copyOfSet"));
+ // Map
+ type = factory.mapType;
+
+ // Map Map.copyOf(Map)
+ name = factory.createString("copyOf");
+ proto = factory.createProto(factory.mapType, factory.mapType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::CollectionsMethods_copyOfMap, "copyOfMap"));
+
// Byte
type = factory.boxedByteType;
@@ -1048,7 +1059,7 @@
private void initializeJava9MethodProviders(DexItemFactory factory) {
// Integer
DexType type = factory.boxedIntType;
- // long Long.parseLong(CharSequence s, int beginIndex, int endIndex, int radix)
+ // int Integer.parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
DexString name = factory.createString("parseInt");
DexProto proto =
factory.createProto(
@@ -1120,17 +1131,6 @@
addProvider(
new MethodGenerator(
method, BackportedMethods::CollectionsMethods_copyOfList, "copyOfList"));
-
- // Map
- type = factory.mapType;
-
- // Map Map.copyOf(Map)
- name = factory.createString("copyOf");
- proto = factory.createProto(factory.mapType, factory.mapType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new MethodGenerator(
- method, BackportedMethods::CollectionsMethods_copyOfMap, "copyOfMap"));
}
private void initializeJava11MethodProviders(DexItemFactory factory) {
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 854f6e9..aacfec7 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
@@ -735,7 +735,7 @@
Set<Instruction> users = eligibleInstance.uniqueUsers();
for (Instruction user : users) {
BasicBlock block = user.getBlock();
- if (!seen.add(block)) {
+ if (block == null || !seen.add(block)) {
continue;
}
@@ -746,8 +746,8 @@
continue;
}
- if (user.isInstanceGet()) {
- if (user.hasUsedOutValue()) {
+ if (instruction.isInstanceGet()) {
+ if (instruction.hasUsedOutValue()) {
replaceFieldReadFromStaticGet(
code, instructionIterator, user.asInstanceGet(), affectedValues);
} else {
@@ -756,7 +756,7 @@
continue;
}
- if (user.isInstancePut()) {
+ if (instruction.isInstancePut()) {
instructionIterator.removeOrReplaceByDebugLocalRead();
continue;
}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index 1fdb08f..bd44c7b 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -5,6 +5,7 @@
import static com.android.tools.r8.naming.ClassNameMapper.MissingFileAction.MISSING_FILE_IS_ERROR;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
+import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.graph.DexField;
@@ -14,9 +15,11 @@
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.utils.BiMapContainer;
import com.android.tools.r8.utils.ChainableStringConsumer;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Reporter;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
@@ -29,9 +32,12 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -43,10 +49,11 @@
}
public static class Builder extends ProguardMap.Builder {
- private final ImmutableMap.Builder<String, ClassNamingForNameMapper.Builder> mapBuilder;
+ private final Map<String, ClassNamingForNameMapper.Builder> mapping = new HashMap<>();
+ private final Map<String, List<ScopedMappingInformation>> scopedMappingInfo = new HashMap<>();
private Builder() {
- this.mapBuilder = ImmutableMap.builder();
+
}
@Override
@@ -54,13 +61,40 @@
String renamedName, String originalName, Position position) {
ClassNamingForNameMapper.Builder classNamingBuilder =
ClassNamingForNameMapper.builder(renamedName, originalName);
- mapBuilder.put(renamedName, classNamingBuilder);
+ mapping.put(renamedName, classNamingBuilder);
return classNamingBuilder;
}
@Override
+ void addScopedMappingInformation(ScopedMappingInformation scopedMappingInformation) {
+ scopedMappingInformation.forEach(
+ (ref, info) ->
+ scopedMappingInfo.computeIfAbsent(ref, ignoreArgument(ArrayList::new)).add(info));
+ }
+
+ @Override
public ClassNameMapper build() {
- return new ClassNameMapper(mapBuilder.build());
+ return new ClassNameMapper(buildClassNameMappings());
+ }
+
+ private ImmutableMap<String, ClassNamingForNameMapper> buildClassNameMappings() {
+ // Ensure that all scoped references have at least the identity in the final mapping.
+ for (String descriptor : scopedMappingInfo.keySet()) {
+ String typename = DescriptorUtils.descriptorToJavaType(descriptor);
+ mapping.computeIfAbsent(typename, t -> ClassNamingForNameMapper.builder(t, t));
+ }
+ // Build the final mapping while amending any entries with the scoped info.
+ ImmutableMap.Builder<String, ClassNamingForNameMapper> builder = ImmutableMap.builder();
+ builder.orderEntriesByValue(Comparator.comparing(x -> x.originalName));
+ mapping.forEach(
+ (renamedName, valueBuilder) -> {
+ String descriptor = DescriptorUtils.javaTypeToDescriptor(renamedName);
+ scopedMappingInfo
+ .getOrDefault(descriptor, Collections.emptyList())
+ .forEach(valueBuilder::addMappingInformation);
+ builder.put(renamedName, valueBuilder.build());
+ });
+ return builder.build();
}
}
@@ -126,17 +160,8 @@
private final ImmutableMap<String, ClassNamingForNameMapper> classNameMappings;
private BiMapContainer<String, String> nameMapping;
-
private final Map<Signature, Signature> signatureMap = new HashMap<>();
- private ClassNameMapper(Map<String, ClassNamingForNameMapper.Builder> classNameMappings) {
- ImmutableMap.Builder<String, ClassNamingForNameMapper> builder = ImmutableMap.builder();
- for(Map.Entry<String, ClassNamingForNameMapper.Builder> entry : classNameMappings.entrySet()) {
- builder.put(entry.getKey(), entry.getValue().build());
- }
- this.classNameMappings = builder.build();
- }
-
private ClassNameMapper(ImmutableMap<String, ClassNamingForNameMapper> classNameMappings) {
this.classNameMappings = classNameMappings;
}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 12ea2a6..fb084f1 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import static com.android.tools.r8.naming.MemberNaming.NoSignature.NO_SIGNATURE;
-
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -14,6 +12,7 @@
import com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics;
import com.android.tools.r8.utils.ChainableStringConsumer;
import com.android.tools.r8.utils.ThrowingConsumer;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.ArrayList;
@@ -41,7 +40,7 @@
private final Map<FieldSignature, MemberNaming> fieldMembers = Maps.newHashMap();
private final Map<String, List<MappedRange>> mappedRangesByName = Maps.newHashMap();
private final Map<String, List<MemberNaming>> mappedFieldNamingsByName = Maps.newHashMap();
- private final Map<Signature, List<MappingInformation>> additionalMappings = Maps.newHashMap();
+ private final List<MappingInformation> additionalMappings = new ArrayList<>();
private Builder(String renamedName, String originalName) {
this.originalName = originalName;
@@ -85,18 +84,12 @@
private ClassNaming.Builder addMappingInformation(
MappingInformation mappingInformation, Consumer<MappingInformation> notAllowedCombination) {
- Signature signature =
- mappingInformation.isSignatureMappingInformation()
- ? mappingInformation.asSignatureMappingInformation().getSignature()
- : NO_SIGNATURE;
- List<MappingInformation> additionalMappingForSignature =
- additionalMappings.computeIfAbsent(signature, ignored -> new ArrayList<>());
- for (MappingInformation information : additionalMappingForSignature) {
+ for (MappingInformation information : additionalMappings) {
if (!information.allowOther(mappingInformation)) {
notAllowedCombination.accept(information);
}
}
- additionalMappingForSignature.add(mappingInformation);
+ additionalMappings.add(mappingInformation);
return this;
}
@@ -120,7 +113,7 @@
fieldMembers,
map,
mappedFieldNamingsByName,
- additionalMappings);
+ ImmutableList.copyOf(additionalMappings));
}
/** The parameters are forwarded to MappedRange constructor, see explanation there. */
@@ -251,7 +244,7 @@
public final Map<String, List<MemberNaming>> mappedFieldNamingsByName;
- private final Map<Signature, List<MappingInformation>> additionalMappings;
+ private final ImmutableList<MappingInformation> additionalMappings;
private ClassNamingForNameMapper(
String renamedName,
@@ -260,13 +253,14 @@
Map<FieldSignature, MemberNaming> fieldMembers,
Map<String, MappedRangesOfName> mappedRangesByRenamedName,
Map<String, List<MemberNaming>> mappedFieldNamingsByName,
- Map<Signature, List<MappingInformation>> additionalMappings) {
+ ImmutableList<MappingInformation> additionalMappings) {
this.renamedName = renamedName;
this.originalName = originalName;
this.methodMembers = ImmutableMap.copyOf(methodMembers);
this.fieldMembers = ImmutableMap.copyOf(fieldMembers);
this.mappedRangesByRenamedName = mappedRangesByRenamedName;
this.mappedFieldNamingsByName = mappedFieldNamingsByName;
+ assert additionalMappings != null;
this.additionalMappings = additionalMappings;
}
@@ -356,13 +350,7 @@
consumer.accept(originalName).accept(" -> ").accept(renamedName).accept(":\n");
// Print all additional mapping information.
- additionalMappings.forEach(
- (signature, mappingInformations) -> {
- assert !mappingInformations.isEmpty();
- for (MappingInformation mappingInformation : mappingInformations) {
- consumer.accept("# " + mappingInformation.serialize()).accept("\n");
- }
- });
+ additionalMappings.forEach(info -> consumer.accept("# " + info.serialize()).accept("\n"));
// Print field member namings.
forAllFieldNaming(m -> consumer.accept(" ").accept(m.toString()).accept("\n"));
@@ -379,7 +367,7 @@
}
}
- public Map<Signature, List<MappingInformation>> getAdditionalMappings() {
+ public List<MappingInformation> getAdditionalMappings() {
return additionalMappings;
}
diff --git a/src/main/java/com/android/tools/r8/naming/MapVersion.java b/src/main/java/com/android/tools/r8/naming/MapVersion.java
new file mode 100644
index 0000000..7069351
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/MapVersion.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, 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.naming;
+
+import com.android.tools.r8.utils.structural.Ordered;
+
+public enum MapVersion implements Ordered<MapVersion> {
+ MapVersionNone("none"),
+ MapVersionExperimental("experimental");
+
+ public static final MapVersion STABLE = MapVersionNone;
+
+ private final String name;
+
+ MapVersion(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static MapVersion fromName(String name) {
+ for (MapVersion version : MapVersion.values()) {
+ if (version.getName().equals(name)) {
+ return version;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index 4a50244..bf0a8dd 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -168,40 +168,6 @@
}
}
- public static class NoSignature extends Signature {
-
- public static final NoSignature NO_SIGNATURE = new NoSignature();
-
- private NoSignature() {
- super("NO SIGNATURE");
- }
-
- @Override
- Signature asRenamed(String renamedName) {
- throw new Unreachable("Should not be called on NoSignature");
- }
-
- @Override
- public SignatureKind kind() {
- throw new Unreachable("Should not be called on NoSignature");
- }
-
- @Override
- public boolean equals(Object o) {
- return o == this;
- }
-
- @Override
- public int hashCode() {
- return 7;
- }
-
- @Override
- void write(Writer builder) throws IOException {
- throw new Unreachable("Should not be called on NoSignature");
- }
- }
-
public static class FieldSignature extends Signature {
public final String type;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMap.java b/src/main/java/com/android/tools/r8/naming/ProguardMap.java
index 221f064..f56e3b8 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMap.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMap.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.naming;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation;
import com.android.tools.r8.position.Position;
public interface ProguardMap {
@@ -13,6 +14,8 @@
String renamedName, String originalName, Position position);
abstract ProguardMap build();
+
+ abstract void addScopedMappingInformation(ScopedMappingInformation scopedMappingInformation);
}
boolean hasMapping(DexType type);
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index 0f94efa..d7ab9c8 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -7,12 +7,15 @@
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.ProguardMap.Builder;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
-import com.android.tools.r8.naming.mappinginformation.SignatureMappingInformation;
+import com.android.tools.r8.naming.mappinginformation.MetaInfMappingInformation;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ClassScopeReference;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ScopeReference;
import com.android.tools.r8.position.TextPosition;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.IdentifierUtils;
import com.android.tools.r8.utils.StringUtils;
-import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.BufferedReader;
@@ -20,7 +23,6 @@
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
/**
@@ -85,6 +87,8 @@
private int lineNo = 0;
private int lineOffset = 0;
private String line;
+ private MapVersion version = MapVersion.MapVersionNone;
+ private ScopeReference implicitSingletonScope = null;
private int peekCodePoint() {
return lineOffset < line.length() ? line.codePointAt(lineOffset) : '\n';
@@ -225,7 +229,7 @@
if (isCommentLineWithJsonBrace()) {
// TODO(b/179665169): Parse the mapping information without doing anything with it, since we
// at this point do not have a global context.
- MappingInformation.fromJsonObject(parseJsonInComment(), diagnosticsHandler, lineNo);
+ parseMappingInformation();
// Skip reading the rest of the line.
lineOffset = line.length();
nextLine();
@@ -248,29 +252,42 @@
expect(':');
ClassNaming.Builder currentClassBuilder =
mapBuilder.classNamingBuilder(after, before, getPosition());
+ implicitSingletonScope = new ClassScopeReference(Reference.classFromTypeName(after));
skipWhitespace();
if (nextLine()) {
- parseMemberMappings(currentClassBuilder);
+ parseMemberMappings(mapBuilder, currentClassBuilder);
}
}
}
- private void parseMemberMappings(ClassNaming.Builder classNamingBuilder) throws IOException {
+ private MappingInformation parseMappingInformation() {
+ MappingInformation info =
+ MappingInformation.fromJsonObject(
+ version, parseJsonInComment(), diagnosticsHandler, lineNo, implicitSingletonScope);
+ if (info == null) {
+ return null;
+ }
+ MetaInfMappingInformation generatorInfo = info.asMetaInfMappingInformation();
+ if (generatorInfo != null) {
+ version = generatorInfo.getMapVersion();
+ }
+ return info;
+ }
+
+ private void parseMemberMappings(Builder mapBuilder, ClassNaming.Builder classNamingBuilder)
+ throws IOException {
MemberNaming lastAddedNaming = null;
MemberNaming activeMemberNaming = null;
Range previousMappedRange = null;
- Map<Signature, SignatureMappingInformation> mappingInformation = Maps.newHashMap();
do {
Object originalRange = null;
Range mappedRange = null;
// Try to parse any information added in comments above member namings
if (isCommentLineWithJsonBrace()) {
- MappingInformation mappingInfo =
- MappingInformation.fromJsonObject(parseJsonInComment(), diagnosticsHandler, lineNo);
+ MappingInformation mappingInfo = parseMappingInformation();
if (mappingInfo != null) {
- if (mappingInfo.isSignatureMappingInformation()) {
- SignatureMappingInformation sigMapInfo = mappingInfo.asSignatureMappingInformation();
- mappingInformation.put(sigMapInfo.getSignature(), sigMapInfo);
+ if (mappingInfo.isScopedMappingInformation()) {
+ mapBuilder.addScopedMappingInformation(mappingInfo.asScopedMappingInformation());
} else {
classNamingBuilder.addMappingInformation(mappingInfo, diagnosticsHandler, lineNo);
}
@@ -336,16 +353,8 @@
}
}
}
- if (mappingInformation.containsKey(signature)) {
- activeMemberNaming =
- new MemberNaming(
- signature,
- mappingInformation.get(signature).apply(signature, renamedName, diagnosticsHandler),
- getPosition());
- } else {
- activeMemberNaming =
- new MemberNaming(signature, signature.asRenamed(renamedName), getPosition());
- }
+ activeMemberNaming =
+ new MemberNaming(signature, signature.asRenamed(renamedName), getPosition());
previousMappedRange = mappedRange;
} while (nextLine());
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index ec947e8..6516e22 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.Version;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.naming.mappinginformation.MetaInfMappingInformation;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.ChainableStringConsumer;
import com.android.tools.r8.utils.ExceptionUtils;
@@ -101,6 +102,17 @@
builder.append("# " + MARKER_KEY_PG_MAP_ID + ": " + id.get() + "\n");
// Turn off linting of the mapping file in some build systems.
builder.append("# common_typos_disable" + "\n");
+ // Emit the R8 specific map-file version.
+ MapVersion mapVersion =
+ options.testing.enableExperimentalMapFileVersion
+ ? MapVersion.MapVersionExperimental
+ : MapVersion.STABLE;
+ if (mapVersion.isGreaterThan(MapVersion.MapVersionNone)) {
+ builder
+ .append("# ")
+ .append(new MetaInfMappingInformation(mapVersion).serialize())
+ .append("\n");
+ }
consumer.accept(builder.toString(), reporter);
}
diff --git a/src/main/java/com/android/tools/r8/naming/SeedMapper.java b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
index 927cf6e..2e5b125 100644
--- a/src/main/java/com/android/tools/r8/naming/SeedMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.utils.Reporter;
import com.google.common.collect.ImmutableMap;
@@ -61,6 +62,11 @@
}
@Override
+ void addScopedMappingInformation(ScopedMappingInformation scopedMappingInformation) {
+ // Not needed.
+ }
+
+ @Override
SeedMapper build() {
reporter.failIfPendingErrors();
return new SeedMapper(ImmutableMap.copyOf(map), mappedToDescriptorNames, reporter);
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
index b0a13ba..d44e5e6 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
@@ -5,15 +5,38 @@
package com.android.tools.r8.naming.mappinginformation;
import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
+import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
-public class CompilerSynthesizedMappingInformation extends MappingInformation {
+public class CompilerSynthesizedMappingInformation extends ScopedMappingInformation {
public static final String ID = "com.android.tools.r8.synthesized";
- public CompilerSynthesizedMappingInformation() {
- super(NO_LINE_NUMBER);
+ public static class Builder extends ScopedMappingInformation.Builder<Builder> {
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ @Override
+ public Builder self() {
+ return this;
+ }
+
+ public CompilerSynthesizedMappingInformation build() {
+ return new CompilerSynthesizedMappingInformation(buildScope());
+ }
+ }
+
+ private CompilerSynthesizedMappingInformation(ImmutableList<ScopeReference> scope) {
+ super(scope);
+ }
+
+ public static Builder builder() {
+ return new Builder();
}
@Override
@@ -32,14 +55,22 @@
}
@Override
- public String serialize() {
- JsonObject result = new JsonObject();
- result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
- return result.toString();
+ protected JsonObject serializeToJsonObject(JsonObject object) {
+ object.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
+ return object;
}
public static CompilerSynthesizedMappingInformation deserialize(
- JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
- return new CompilerSynthesizedMappingInformation();
+ MapVersion version,
+ JsonObject object,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber,
+ ScopeReference implicitSingletonScope) {
+ if (version.isLessThan(MapVersion.MapVersionExperimental)) {
+ return null;
+ }
+ return builder()
+ .deserializeFromJsonObject(object, implicitSingletonScope, diagnosticsHandler, lineNumber)
+ .build();
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java
index 87b3e7b..38eabbf 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.naming.mappinginformation;
import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
@@ -53,7 +54,11 @@
}
public static FileNameInformation build(
- JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
+ MapVersion version,
+ JsonObject object,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber) {
+ // Source file information is valid for all map file versions.
try {
JsonElement fileName =
getJsonElementFromObject(object, diagnosticsHandler, lineNumber, FILE_NAME_KEY, ID);
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index cb0708f..0ef03d0 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -5,6 +5,8 @@
package com.android.tools.r8.naming.mappinginformation;
import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ScopeReference;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -26,11 +28,19 @@
public abstract String serialize();
- public boolean isSignatureMappingInformation() {
+ public boolean isScopedMappingInformation() {
return false;
}
- public SignatureMappingInformation asSignatureMappingInformation() {
+ public ScopedMappingInformation asScopedMappingInformation() {
+ return null;
+ }
+
+ public boolean isMetaInfMappingInformation() {
+ return false;
+ }
+
+ public MetaInfMappingInformation asMetaInfMappingInformation() {
return null;
}
@@ -42,14 +52,6 @@
return null;
}
- public boolean isMethodSignatureChangedInformation() {
- return false;
- }
-
- public MethodSignatureChangedInformation asMethodSignatureChangedInformation() {
- return null;
- }
-
public boolean isCompilerSynthesizedMappingInformation() {
return false;
}
@@ -61,7 +63,11 @@
public abstract boolean allowOther(MappingInformation information);
public static MappingInformation fromJsonObject(
- JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
+ MapVersion version,
+ JsonObject object,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber,
+ ScopeReference implicitSingletonScope) {
if (object == null) {
diagnosticsHandler.info(MappingInformationDiagnostics.notValidJson(lineNumber));
return null;
@@ -78,16 +84,28 @@
MappingInformationDiagnostics.notValidString(lineNumber, MAPPING_ID_KEY));
return null;
}
- switch (idString) {
- case MethodSignatureChangedInformation.ID:
- return MethodSignatureChangedInformation.build(object, diagnosticsHandler, lineNumber);
+ return deserialize(
+ idString, version, object, diagnosticsHandler, lineNumber, implicitSingletonScope);
+ }
+
+ private static MappingInformation deserialize(
+ String id,
+ MapVersion version,
+ JsonObject object,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber,
+ ScopeReference implicitSingletonScope) {
+ switch (id) {
+ case MetaInfMappingInformation.ID:
+ return MetaInfMappingInformation.deserialize(
+ version, object, diagnosticsHandler, lineNumber);
case FileNameInformation.ID:
- return FileNameInformation.build(object, diagnosticsHandler, lineNumber);
+ return FileNameInformation.build(version, object, diagnosticsHandler, lineNumber);
case CompilerSynthesizedMappingInformation.ID:
return CompilerSynthesizedMappingInformation.deserialize(
- object, diagnosticsHandler, lineNumber);
+ version, object, diagnosticsHandler, lineNumber, implicitSingletonScope);
default:
- diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, idString));
+ diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, id));
return null;
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MetaInfMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MetaInfMappingInformation.java
new file mode 100644
index 0000000..ba6bb72
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MetaInfMappingInformation.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2021, 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.naming.mappinginformation;
+
+import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.noKeyForObjectWithId;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+
+public class MetaInfMappingInformation extends MappingInformation {
+
+ public static final String ID = "com.android.tools.r8.metainf";
+ public static final String MAP_VERSION_KEY = "map-version";
+
+ private final MapVersion mapVersion;
+
+ public MetaInfMappingInformation(MapVersion mapVersion) {
+ super(NO_LINE_NUMBER);
+ this.mapVersion = mapVersion;
+ }
+
+ @Override
+ public boolean isMetaInfMappingInformation() {
+ return true;
+ }
+
+ @Override
+ public MetaInfMappingInformation asMetaInfMappingInformation() {
+ return this;
+ }
+
+ @Override
+ public boolean allowOther(MappingInformation information) {
+ return !information.isMetaInfMappingInformation();
+ }
+
+ public MapVersion getMapVersion() {
+ return mapVersion;
+ }
+
+ @Override
+ public String serialize() {
+ JsonObject result = new JsonObject();
+ result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
+ result.add(MAP_VERSION_KEY, new JsonPrimitive(mapVersion.getName()));
+ return result.toString();
+ }
+
+ public static MetaInfMappingInformation deserialize(
+ MapVersion version,
+ JsonObject object,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber) {
+ // Parsing the generator information must support parsing at all map versions as it itself is
+ // what establishes the version.
+ String mapVersion = object.get(MAP_VERSION_KEY).getAsString();
+ if (mapVersion == null) {
+ noKeyForObjectWithId(lineNumber, MAP_VERSION_KEY, MAPPING_ID_KEY, ID);
+ return null;
+ }
+ MapVersion mapVersion1 = MapVersion.fromName(mapVersion);
+ if (mapVersion1 == null) {
+ return null;
+ }
+ return new MetaInfMappingInformation(mapVersion1);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java
deleted file mode 100644
index 8bb023d..0000000
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java
+++ /dev/null
@@ -1,258 +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.naming.mappinginformation;
-
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.invalidParameterInformationObject;
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.invalidValueForObjectWithId;
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.tooManyEntriesForParameterInformation;
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.tooManyInformationalParameters;
-
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-
-/**
- * The MethodSignatureChangedInformation structure adds extra information regarding the mapped
- * method signature that is otherwise not available in the existing proguard mapping format. The
- * JSON-structure is as follows:
- *
- * <pre>
- * {
- * "id": "argumentsChanged",
- * "signature": { methodSignature },
- * "returnType": "java.lang.String",
- * "receiver": false,
- * "params": [
- * [1], // <-- parameter with original index 1 (starting index based on receiver) is removed.
- * [2, Foo] // <-- parameter with index 2 has type Foo
- * ]
- * }
- * </pre>
- */
-public class MethodSignatureChangedInformation extends SignatureMappingInformation {
-
- private ParameterInformation[] argumentInfos;
- private final boolean receiver;
- private final String returnType;
- private final MethodSignature signature;
-
- public static final String ID = "methodSignatureChanged";
- private static final String RETURN_TYPE_KEY = "returnType";
- private static final String PARAMS_KEY = "params";
- private static final String RECEIVER_KEY = "receiver";
-
- @Override
- public String serialize() {
- JsonObject result = new JsonObject();
- serializeMethodSignature(result, signature);
- result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
- result.add(RECEIVER_KEY, new JsonPrimitive(receiver));
- result.add(RETURN_TYPE_KEY, new JsonPrimitive(returnType));
- JsonArray arguments = new JsonArray();
- for (ParameterInformation argInfo : argumentInfos) {
- arguments.add(argInfo.serialize());
- }
- result.add(PARAMS_KEY, arguments);
- return result.toString();
- }
-
- @Override
- public boolean allowOther(MappingInformation information) {
- return !information.isMethodSignatureChangedInformation();
- }
-
- @Override
- public Signature getSignature() {
- return signature;
- }
-
- @Override
- public Signature apply(
- Signature originalSignature, String renamedName, DiagnosticsHandler diagnosticsHandler) {
- if (originalSignature == null || !originalSignature.isMethodSignature()) {
- assert false : "Should only call apply for method signature";
- return originalSignature;
- }
- MethodSignature signature = originalSignature.asMethodSignature();
- String type = signature.type;
- String[] parameters = signature.parameters;
- int numberOfArgumentsRemoved = getNumberOfArgumentsRemoved();
- if (numberOfArgumentsRemoved > parameters.length) {
- // The mapping information is not up to date with the current signature.
- diagnosticsHandler.warning(tooManyInformationalParameters(getLineNumber()));
- return new MethodSignature(renamedName, type, parameters);
- }
- String[] newParameters = new String[parameters.length - numberOfArgumentsRemoved];
- int insertIndex = 0;
- for (int i = 0; i < parameters.length; i++) {
- ParameterInformation argInfo = getParameterInformation(i);
- if (argInfo != null && argInfo.getType() == null) {
- // Argument has been removed.
- } else {
- if (insertIndex >= newParameters.length) {
- // The mapping information is not up to date with the current signature.
- diagnosticsHandler.warning(tooManyInformationalParameters(getLineNumber()));
- return new MethodSignature(renamedName, type, parameters);
- } else if (argInfo == null) {
- // Unchanged, take current parameter.
- newParameters[insertIndex++] = parameters[i];
- } else {
- newParameters[insertIndex++] = argInfo.getType();
- }
- }
- }
- assert insertIndex == newParameters.length;
- return new MethodSignature(renamedName, getReturnType(), newParameters);
- }
-
- @Override
- public boolean isMethodSignatureChangedInformation() {
- return true;
- }
-
- public int getNumberOfArgumentsRemoved() {
- int removedCount = 0;
- for (ParameterInformation argInfo : argumentInfos) {
- if (argInfo.type == null) {
- removedCount++;
- }
- }
- return removedCount;
- }
-
- public boolean hasReceiver() {
- return receiver;
- }
-
- public String getReturnType() {
- return returnType;
- }
-
- public ParameterInformation getParameterInformation(int index) {
- int subtractIndex = receiver ? 1 : 0;
- for (int i = 0; i < argumentInfos.length; i++) {
- if (argumentInfos[i].index - subtractIndex == index) {
- return argumentInfos[i];
- }
- }
- return null;
- }
-
- @Override
- public MethodSignatureChangedInformation asMethodSignatureChangedInformation() {
- return this;
- }
-
- private MethodSignatureChangedInformation(
- MethodSignature signature,
- String returnType,
- boolean hasReceiver,
- ParameterInformation[] argumentInfos,
- int lineNumber) {
- super(lineNumber);
- this.signature = signature;
- this.argumentInfos = argumentInfos;
- this.returnType = returnType;
- this.receiver = hasReceiver;
- }
-
- public static MappingInformation build(
- JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
- try {
- JsonElement returnTypeElement =
- getJsonElementFromObject(object, diagnosticsHandler, lineNumber, RETURN_TYPE_KEY, ID);
- JsonElement receiverElement =
- getJsonElementFromObject(object, diagnosticsHandler, lineNumber, RECEIVER_KEY, ID);
- JsonElement argsElement =
- getJsonElementFromObject(object, diagnosticsHandler, lineNumber, PARAMS_KEY, ID);
- MethodSignature signature = getMethodSignature(object, ID, diagnosticsHandler, lineNumber);
- if (signature == null
- || returnTypeElement == null
- || receiverElement == null
- || argsElement == null) {
- return null;
- }
- JsonArray argumentsArray = argsElement.getAsJsonArray();
- if (argumentsArray == null) {
- return null;
- }
- ParameterInformation[] args = new ParameterInformation[argumentsArray.size()];
- for (int i = 0; i < argumentsArray.size(); i++) {
- args[i] =
- ParameterInformation.fromJsonArray(
- argumentsArray.get(i).getAsJsonArray(), diagnosticsHandler, lineNumber);
- }
- return new MethodSignatureChangedInformation(
- signature,
- returnTypeElement.getAsString(),
- receiverElement.getAsBoolean(),
- args,
- lineNumber);
- } catch (UnsupportedOperationException | IllegalStateException ignored) {
- diagnosticsHandler.info(invalidValueForObjectWithId(lineNumber, MAPPING_ID_KEY, ID));
- return null;
- }
- }
-
- public static class ParameterInformation {
- private final int index;
- private final String type;
-
- public int getIndex() {
- return index;
- }
-
- public String getType() {
- return type;
- }
-
- private ParameterInformation(int index, String type) {
- this.index = index;
- this.type = type;
- }
-
- static ParameterInformation fromJsonArray(
- JsonArray argumentInfo, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
- assert argumentInfo != null;
- try {
- if (argumentInfo.size() > 2) {
- diagnosticsHandler.info(tooManyEntriesForParameterInformation(lineNumber));
- return null;
- }
- int index = argumentInfo.get(0).getAsInt();
- if (argumentInfo.size() == 1) {
- // This is a removed argument - no type information
- return new ParameterInformation(index, null);
- } else {
- return new ParameterInformation(index, argumentInfo.get(1).getAsString());
- }
- } catch (UnsupportedOperationException | IllegalStateException ignored) {
- diagnosticsHandler.info(invalidParameterInformationObject(lineNumber));
- return null;
- }
- }
-
- public static ParameterInformation buildRemovedParameterInformation(int index) {
- return new ParameterInformation(index, null);
- }
-
- public static ParameterInformation buildChangedParameterInformation(int index, String type) {
- return new ParameterInformation(index, type);
- }
-
- JsonArray serialize() {
- JsonArray serializedArray = new JsonArray();
- serializedArray.add(index);
- if (type != null) {
- serializedArray.add(type);
- }
- return serializedArray;
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java
new file mode 100644
index 0000000..deb0440
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java
@@ -0,0 +1,126 @@
+// Copyright (c) 2021, 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.naming.mappinginformation;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.function.BiConsumer;
+
+public abstract class ScopedMappingInformation extends MappingInformation {
+
+ // Abstraction for the items referenced in a scope.
+ // We should consider passing in a scope reference factory.
+ // For reading we likely want to map directly to DexItem, whereas for writing we likely want
+ // to map to java.lang.String with the post-minification names.
+ public abstract static class ScopeReference {
+
+ public static ScopeReference fromReferenceString(String referenceString) {
+ if (DescriptorUtils.isClassDescriptor(referenceString)) {
+ return new ClassScopeReference(Reference.classFromDescriptor(referenceString));
+ }
+ throw new Unimplemented("No support for reference: " + referenceString);
+ }
+
+ public abstract String toReferenceString();
+
+ @Override
+ public String toString() {
+ return toReferenceString();
+ }
+ }
+
+ public static class ClassScopeReference extends ScopeReference {
+ final ClassReference reference;
+
+ public ClassScopeReference(ClassReference reference) {
+ this.reference = reference;
+ }
+
+ @Override
+ public String toReferenceString() {
+ return reference.getDescriptor();
+ }
+ }
+
+ public abstract static class Builder<B extends Builder<B>> {
+ public abstract String getId();
+
+ public abstract B self();
+
+ private final ImmutableList.Builder<ScopeReference> scope = ImmutableList.builder();
+
+ public B deserializeFromJsonObject(
+ JsonObject object,
+ ScopeReference implicitSingletonScope,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber) {
+ JsonArray scopeArray = object.getAsJsonArray(SCOPE_KEY);
+ if (scopeArray != null) {
+ for (JsonElement element : scopeArray) {
+ addScopeReference(ScopeReference.fromReferenceString(element.getAsString()));
+ }
+ } else if (implicitSingletonScope != null) {
+ addScopeReference(implicitSingletonScope);
+ } else {
+ diagnosticsHandler.info(
+ MappingInformationDiagnostics.noKeyForObjectWithId(
+ lineNumber, SCOPE_KEY, MAPPING_ID_KEY, getId()));
+ }
+ return self();
+ }
+
+ public B addScopeReference(ScopeReference reference) {
+ scope.add(reference);
+ return self();
+ }
+
+ public ImmutableList<ScopeReference> buildScope() {
+ return scope.build();
+ }
+ }
+
+ public static final String SCOPE_KEY = "scope";
+
+ private final ImmutableList<ScopeReference> scopeReferences;
+
+ public ScopedMappingInformation(ImmutableList<ScopeReference> scopeReferences) {
+ super(NO_LINE_NUMBER);
+ this.scopeReferences = scopeReferences;
+ assert !scopeReferences.isEmpty() : "Expected a scope. Global scope not yet in use.";
+ }
+
+ protected abstract JsonObject serializeToJsonObject(JsonObject object);
+
+ @Override
+ public final boolean isScopedMappingInformation() {
+ return true;
+ }
+
+ @Override
+ public final ScopedMappingInformation asScopedMappingInformation() {
+ return this;
+ }
+
+ public void forEach(BiConsumer<String, ScopedMappingInformation> fn) {
+ for (ScopeReference reference : scopeReferences) {
+ fn.accept(reference.toReferenceString(), this);
+ }
+ }
+
+ @Override
+ public final String serialize() {
+ JsonObject object = serializeToJsonObject(new JsonObject());
+ JsonArray scopeArray = new JsonArray();
+ scopeReferences.forEach(ref -> scopeArray.add(ref.toReferenceString()));
+ object.add(SCOPE_KEY, scopeArray);
+ return object.toString();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java
deleted file mode 100644
index aba33bb..0000000
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java
+++ /dev/null
@@ -1,64 +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.naming.mappinginformation;
-
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-
-public abstract class SignatureMappingInformation extends MappingInformation {
-
- private static final String SIGNATURE_KEY = "signature";
-
- SignatureMappingInformation(int lineNumber) {
- super(lineNumber);
- }
-
- @Override
- public boolean isSignatureMappingInformation() {
- return true;
- }
-
- @Override
- public SignatureMappingInformation asSignatureMappingInformation() {
- return this;
- }
-
- public abstract Signature getSignature();
-
- public abstract Signature apply(
- Signature originalSignature, String renamedName, DiagnosticsHandler diagnosticsHandler);
-
- JsonObject serializeMethodSignature(JsonObject object, MethodSignature signature) {
- JsonArray signatureArr = new JsonArray();
- signatureArr.add(signature.type);
- signatureArr.add(signature.name);
- for (String parameter : signature.parameters) {
- signatureArr.add(parameter);
- }
- object.add(SIGNATURE_KEY, signatureArr);
- return object;
- }
-
- static MethodSignature getMethodSignature(
- JsonObject object, String id, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
- JsonElement signatureElement =
- getJsonElementFromObject(object, diagnosticsHandler, lineNumber, SIGNATURE_KEY, id);
- if (signatureElement == null || !signatureElement.isJsonArray()) {
- return null;
- }
- // Signature will be [returnType, name, param1, param2, ...].
- JsonArray signature = signatureElement.getAsJsonArray();
- String[] parameters = new String[signature.size() - 2];
- for (int i = 2; i < signature.size(); i++) {
- parameters[i - 2] = signature.get(i).getAsString();
- }
- return new MethodSignature(
- signature.get(1).getAsString(), signature.get(0).getAsString(), parameters);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java b/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
index a8e5394..4784f09 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
@@ -4,9 +4,10 @@
package com.android.tools.r8.retrace;
+import static com.android.tools.r8.retrace.internal.StackTraceRegularExpressionParser.DEFAULT_REGULAR_EXPRESSION;
+
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.Keep;
-import com.android.tools.r8.retrace.internal.StackTraceRegularExpressionParser;
/**
* The base options for running retrace with support for continuously retrace strings without
@@ -60,13 +61,17 @@
return new Builder(diagnosticsHandler);
}
+ public static String defaultRegularExpression() {
+ return DEFAULT_REGULAR_EXPRESSION;
+ }
+
@Keep
public static class Builder {
private boolean isVerbose;
private final DiagnosticsHandler diagnosticsHandler;
private ProguardMapProducer proguardMapProducer;
- private String regularExpression = StackTraceRegularExpressionParser.DEFAULT_REGULAR_EXPRESSION;
+ private String regularExpression = defaultRegularExpression();
Builder(DiagnosticsHandler diagnosticsHandler) {
this.diagnosticsHandler = diagnosticsHandler;
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
index 15fdfdc..6bbc26a 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -4,7 +4,6 @@
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;
@@ -234,15 +233,11 @@
@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);
- }
+ if (mapper != null) {
+ for (MappingInformation mappingInformation : mapper.getAdditionalMappings()) {
+ if (mappingInformation.isFileNameInformation()) {
+ return new RetraceSourceFileResultImpl(
+ mappingInformation.asFileNameInformation().getFileName(), false);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index 34c11ee..a561761 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -72,6 +72,10 @@
DexDefinition holder,
DexAnnotation annotation,
boolean isAnnotationTypeLive) {
+ // If we cannot run the AnnotationRemover we are keeping the annotation.
+ if (!appView.options().isShrinking()) {
+ return true;
+ }
ProguardKeepAttributes config =
appView.options().getProguardConfiguration() != null
? appView.options().getProguardConfiguration().getKeepAttributes()
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 7181e84..523552a 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -42,7 +42,7 @@
R(30),
S(31);
- public static final AndroidApiLevel LATEST = R;
+ public static final AndroidApiLevel LATEST = S;
public static final int magicApiLevelUsedByAndroidPlatformBuild = 10000;
@@ -150,6 +150,8 @@
return P;
case 29:
return Q;
+ case 30:
+ return R;
default:
return LATEST;
}
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java
index e9557fa..f06f3d7 100644
--- a/src/main/java/com/android/tools/r8/utils/DexVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -38,6 +38,7 @@
public static DexVersion getDexVersion(AndroidApiLevel androidApiLevel) {
switch (androidApiLevel) {
+ case S:
case R:
case Q:
case P:
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 83a2245..ee29d30 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1380,6 +1380,8 @@
public Consumer<ProgramMethod> callSiteOptimizationInfoInspector = null;
public Predicate<DexMethod> cfByteCodePassThrough = null;
+
+ public boolean enableExperimentalMapFileVersion = false;
}
@VisibleForTesting
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 f8ad5bb..aba61ee 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -49,6 +49,8 @@
import com.android.tools.r8.naming.Range;
import com.android.tools.r8.naming.mappinginformation.CompilerSynthesizedMappingInformation;
import com.android.tools.r8.naming.mappinginformation.FileNameInformation;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ClassScopeReference;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.retrace.internal.RetraceUtils;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
@@ -265,10 +267,7 @@
}
public static ClassNameMapper run(
- AppView<AppInfoWithClassHierarchy> appView,
- DexApplication application,
- AndroidApp inputApp,
- NamingLens namingLens) {
+ AppView<?> appView, DexApplication application, AndroidApp inputApp, NamingLens namingLens) {
// For finding methods in kotlin files based on SourceDebugExtensions, we use a line method map.
// We create it here to ensure it is only reading class files once.
CfLineToMethodMapper cfLineToMethodMapper = new CfLineToMethodMapper(inputApp);
@@ -284,12 +283,12 @@
// It depends on whether any methods/fields are renamed or some methods contain positions.
// Create a supplier which creates a new, cached ClassNaming.Builder on-demand.
DexType originalType = appView.graphLens().getOriginalType(clazz.type);
- DexString renamedClassName = namingLens.lookupDescriptor(clazz.getType());
+ DexString renamedDescriptor = namingLens.lookupDescriptor(clazz.getType());
Supplier<ClassNaming.Builder> onDemandClassNamingBuilder =
Suppliers.memoize(
() ->
classNameMapperBuilder.classNamingBuilder(
- DescriptorUtils.descriptorToJavaType(renamedClassName.toString()),
+ DescriptorUtils.descriptorToJavaType(renamedDescriptor.toString()),
originalType.toSourceString(),
com.android.tools.r8.position.Position.UNKNOWN));
@@ -302,14 +301,19 @@
}
}
- if (isSyntheticClass) {
+ if (isSyntheticClass && appView.options().testing.enableExperimentalMapFileVersion) {
onDemandClassNamingBuilder
.get()
- .addMappingInformation(new CompilerSynthesizedMappingInformation());
+ .addMappingInformation(
+ CompilerSynthesizedMappingInformation.builder()
+ .addScopeReference(
+ new ClassScopeReference(
+ Reference.classFromDescriptor(renamedDescriptor.toString())))
+ .build());
}
// If the class is renamed add it to the classNamingBuilder.
- addClassToClassNaming(originalType, renamedClassName, onDemandClassNamingBuilder);
+ addClassToClassNaming(originalType, renamedDescriptor, onDemandClassNamingBuilder);
// First transfer renamed fields to classNamingBuilder.
addFieldsToClassNaming(
@@ -462,10 +466,11 @@
}
private static boolean verifyMethodsAreKeptDirectlyOrIndirectly(
- AppView<AppInfoWithClassHierarchy> appView, List<DexEncodedMethod> methods) {
- if (appView.options().isGeneratingClassFiles()) {
+ AppView<?> appView, List<DexEncodedMethod> methods) {
+ if (appView.options().isGeneratingClassFiles() || !appView.appInfo().hasClassHierarchy()) {
return true;
}
+ AppInfoWithClassHierarchy appInfo = appView.appInfo().withClassHierarchy();
KeepInfoCollection keepInfo = appView.getKeepInfo();
boolean allSeenAreInstanceInitializers = true;
DexString originalName = null;
@@ -487,7 +492,7 @@
// We use the same name for interface names even if it has different types.
DexProgramClass clazz = appView.definitionForProgramType(method.getHolderType());
DexClassAndMethod lookupResult =
- appView.appInfo().lookupMaximallySpecificMethod(clazz, method.getReference());
+ appInfo.lookupMaximallySpecificMethod(clazz, method.getReference());
if (lookupResult == null) {
// We cannot rename methods we cannot look up.
continue;
diff --git a/src/test/examples/multidex002/ref-list-1.txt b/src/test/examples/multidex002/ref-list-1.txt
index 5fbe5c1..36de405 100644
--- a/src/test/examples/multidex002/ref-list-1.txt
+++ b/src/test/examples/multidex002/ref-list-1.txt
@@ -16,8 +16,13 @@
Lmultidex002/MainActivity;
Lmultidex002/Referenced;
Lmultidex002/ReferencedByAnnotation;
+Lmultidex002/ReferencedByAnnotationWithOtherReferences$1;
+Lmultidex002/ReferencedByAnnotationWithOtherReferences$2;
Lmultidex002/ReferencedByAnnotationWithOtherReferences;
+Lmultidex002/ReferencedByClassInAnnotation$1;
+Lmultidex002/ReferencedByClassInAnnotation$2;
Lmultidex002/ReferencedByClassInAnnotation;
+Lmultidex002/ReferencedByEnum;
Lmultidex002/ReferencedByInterface;
Lmultidex002/TestApplication;
Lmultidex002/fakelibrary/MultiDex$V14;
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 67eeeb0..d299224 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -28,6 +28,8 @@
return new D8TestBuilder(state, D8Command.builder(state.getDiagnosticsHandler()), backend);
}
+ private StringBuilder proguardMapOutputBuilder = null;
+
@Override
D8TestBuilder self() {
return this;
@@ -65,7 +67,12 @@
Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
throws CompilationFailedException {
ToolHelper.runD8(builder, optionsConsumer);
- return new D8TestCompileResult(getState(), app.get(), minApiLevel, getOutputMode());
+ return new D8TestCompileResult(
+ getState(), app.get(), minApiLevel, getOutputMode(), getMapContent());
+ }
+
+ private String getMapContent() {
+ return proguardMapOutputBuilder == null ? null : proguardMapOutputBuilder.toString();
}
public D8TestBuilder setIntermediate(boolean intermediate) {
@@ -106,4 +113,14 @@
}
return self();
}
+
+ // TODO(b/183125319): Make this the default as part of API support in D8.
+ public D8TestBuilder internalEnableMappingOutput() {
+ assert proguardMapOutputBuilder == null;
+ proguardMapOutputBuilder = new StringBuilder();
+ // TODO(b/183125319): Use the API once supported in D8.
+ addOptionsModification(
+ o -> o.proguardMapConsumer = (s, h) -> proguardMapOutputBuilder.append(s));
+ return self();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/D8TestCompileResult.java b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
index b5fccb8..e36ff2d 100644
--- a/src/test/java/com/android/tools/r8/D8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
@@ -9,8 +9,12 @@
import java.util.Set;
public class D8TestCompileResult extends TestCompileResult<D8TestCompileResult, D8TestRunResult> {
- D8TestCompileResult(TestState state, AndroidApp app, int minApiLevel, OutputMode outputMode) {
+ private final String proguardMap;
+
+ D8TestCompileResult(
+ TestState state, AndroidApp app, int minApiLevel, OutputMode outputMode, String proguardMap) {
super(state, app, minApiLevel, outputMode);
+ this.proguardMap = proguardMap;
}
@Override
@@ -38,8 +42,12 @@
return state.getStderr();
}
+ public String getProguardMap() {
+ return proguardMap;
+ }
+
@Override
public D8TestRunResult createRunResult(TestRuntime runtime, ProcessResult result) {
- return new D8TestRunResult(app, runtime, result);
+ return new D8TestRunResult(app, runtime, result, proguardMap);
}
}
diff --git a/src/test/java/com/android/tools/r8/D8TestRunResult.java b/src/test/java/com/android/tools/r8/D8TestRunResult.java
index 4e13e54..d0fe6fb 100644
--- a/src/test/java/com/android/tools/r8/D8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestRunResult.java
@@ -4,17 +4,31 @@
package com.android.tools.r8;
+import static org.junit.Assert.assertNotNull;
+
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.IOException;
public class D8TestRunResult extends SingleTestRunResult<D8TestRunResult> {
- public D8TestRunResult(AndroidApp app, TestRuntime runtime, ProcessResult result) {
+ private final String proguardMap;
+
+ public D8TestRunResult(
+ AndroidApp app, TestRuntime runtime, ProcessResult result, String proguardMap) {
super(app, runtime, result);
+ this.proguardMap = proguardMap;
}
@Override
protected D8TestRunResult self() {
return this;
}
+
+ @Override
+ protected CodeInspector internalGetCodeInspector() throws IOException {
+ assertNotNull(app);
+ return proguardMap == null ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/R8TestRunResult.java b/src/test/java/com/android/tools/r8/R8TestRunResult.java
index 028ed02..f35f686 100644
--- a/src/test/java/com/android/tools/r8/R8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestRunResult.java
@@ -57,23 +57,11 @@
}
@Override
- public CodeInspector inspector() throws IOException, ExecutionException {
- // See comment in base class.
- assertSuccess();
+ protected CodeInspector internalGetCodeInspector() throws IOException {
assertNotNull(app);
return new CodeInspector(app, proguardMap);
}
- @Override
- public <E extends Throwable> R8TestRunResult inspectFailure(
- ThrowingConsumer<CodeInspector, E> consumer) throws IOException, ExecutionException, E {
- assertFailure();
- assertNotNull(app);
- CodeInspector codeInspector = new CodeInspector(app, proguardMap);
- consumer.accept(codeInspector);
- return self();
- }
-
public <E extends Throwable> R8TestRunResult inspectOriginalStackTrace(
ThrowingConsumer<StackTrace, E> consumer) throws E {
consumer.accept(getOriginalStackTrace());
@@ -81,9 +69,8 @@
}
public <E extends Throwable> R8TestRunResult inspectOriginalStackTrace(
- ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer)
- throws E, IOException, ExecutionException {
- consumer.accept(getOriginalStackTrace(), new CodeInspector(app, proguardMap));
+ ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer) throws E, IOException {
+ consumer.accept(getOriginalStackTrace(), internalGetCodeInspector());
return self();
}
@@ -100,7 +87,7 @@
public <E extends Throwable> R8TestRunResult inspectStackTrace(
ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer) throws E, IOException {
- consumer.accept(getStackTrace(), new CodeInspector(app, proguardMap));
+ consumer.accept(getStackTrace(), internalGetCodeInspector());
return self();
}
diff --git a/src/test/java/com/android/tools/r8/SingleTestRunResult.java b/src/test/java/com/android/tools/r8/SingleTestRunResult.java
index d532547..07e0736 100644
--- a/src/test/java/com/android/tools/r8/SingleTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/SingleTestRunResult.java
@@ -90,12 +90,16 @@
return self();
}
+ protected CodeInspector internalGetCodeInspector() throws IOException {
+ assertNotNull(app);
+ return new CodeInspector(app);
+ }
+
public CodeInspector inspector() throws IOException, ExecutionException {
// Inspection post run implies success. If inspection of an invalid program is needed it should
// be done on the compilation result or on the input.
assertSuccess();
- assertNotNull(app);
- return new CodeInspector(app);
+ return internalGetCodeInspector();
}
@Override
@@ -107,10 +111,9 @@
}
public <E extends Throwable> RR inspectFailure(ThrowingConsumer<CodeInspector, E> consumer)
- throws IOException, ExecutionException, E {
+ throws IOException, E {
assertFailure();
- assertNotNull(app);
- CodeInspector inspector = new CodeInspector(app);
+ CodeInspector inspector = internalGetCodeInspector();
consumer.accept(inspector);
return self();
}
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index a6c4924..766fb0f 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -224,6 +224,11 @@
}
}
+ public T enableExperimentalMapFileVersion() {
+ addOptionsModification(o -> o.testing.enableExperimentalMapFileVersion = true);
+ return self();
+ }
+
@FunctionalInterface
public interface DiagnosticsConsumer {
void accept(TestDiagnosticMessages diagnostics);
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 18037be..e9a47e3 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -825,8 +825,6 @@
case J_MR1:
case J_MR2:
case K_WATCH:
- // TODO(b/1813562600): Add android jar for S.
- case S:
return false;
default:
return true;
diff --git a/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerTest.java b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerTest.java
new file mode 100644
index 0000000..a3e284e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerTest.java
@@ -0,0 +1,172 @@
+// Copyright (c) 2021, 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.cf;
+
+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;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** This is a reproduction of b/183285081 */
+@RunWith(Parameterized.class)
+public class StackMapForAlwaysThrowingInitializerTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ public StackMapForAlwaysThrowingInitializerTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+ .run(parameters.getRuntime(), StackMapForThrowingInitializerTest.Main.class, "")
+ .assertFailureWithErrorThatThrows(IllegalArgumentException.class);
+ }
+
+ /**
+ * The dump below checks what happens when we clobber the uninitialized this pointer with straight
+ * line code:
+ *
+ * <pre>
+ * public Main(Object obj, String str) {
+ * this = str <-- clobber the uninitialized this pointer
+ * throw new IllegalArgumentException();
+ * }
+ * </pre>
+ */
+ public static class StackMapForThrowingInitializerTest$MainDump implements Opcodes {
+
+ public static byte[] dump() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ FieldVisitor fieldVisitor;
+ MethodVisitor methodVisitor;
+
+ classWriter.visit(
+ V1_8,
+ ACC_PUBLIC,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ null,
+ "java/lang/Object",
+ null);
+
+ {
+ fieldVisitor =
+ classWriter.visitField(
+ ACC_PRIVATE | ACC_FINAL, "str", "Ljava/lang/String;", null, null);
+ fieldVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ methodVisitor.visitFieldInsn(
+ PUTFIELD,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "str",
+ "Ljava/lang/String;");
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 2);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC, "<init>", "(Ljava/lang/Object;Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitVarInsn(ASTORE, 0);
+ methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false);
+ methodVisitor.visitInsn(ATHROW);
+ methodVisitor.visitMaxs(2, 3);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(ARRAYLENGTH);
+ Label label0 = new Label();
+ methodVisitor.visitJumpInsn(IFNE, label0);
+ methodVisitor.visitTypeInsn(
+ NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitInsn(ACONST_NULL);
+ methodVisitor.visitLdcInsn("foo");
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;)V",
+ false);
+ Label label1 = new Label();
+ methodVisitor.visitJumpInsn(GOTO, label1);
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/io/PrintStream"});
+ methodVisitor.visitTypeInsn(
+ NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitLdcInsn(
+ Type.getType("Lcom/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main;"));
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitInsn(AALOAD);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;)V",
+ false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "toString",
+ "()Ljava/lang/String;",
+ false);
+ methodVisitor.visitLabel(label1);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 1,
+ new Object[] {"[Ljava/lang/String;"},
+ 2,
+ new Object[] {"java/io/PrintStream", "java/lang/Object"});
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(6, 1);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerWithControlFlowTest.java b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerWithControlFlowTest.java
new file mode 100644
index 0000000..2455984
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerWithControlFlowTest.java
@@ -0,0 +1,194 @@
+// Copyright (c) 2021, 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.cf;
+
+import static org.hamcrest.CoreMatchers.containsString;
+
+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;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** This is a reproduction of b/183285081 */
+@RunWith(Parameterized.class)
+public class StackMapForAlwaysThrowingInitializerWithControlFlowTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ public StackMapForAlwaysThrowingInitializerWithControlFlowTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+ .run(parameters.getRuntime(), StackMapForThrowingInitializerTest.Main.class, "")
+ .assertFailureWithErrorThatThrows(VerifyError.class)
+ .assertFailureWithErrorThatMatches(
+ containsString("Current frame's flags are not assignable to stack map frame's"));
+ }
+
+ /**
+ * The dump below checks what happens when we clobber the uninitialized this pointer and have
+ * control flow:
+ *
+ * <pre>
+ * public Main(Object obj, String str) {
+ * this = str <-- clobber the uninitialized this pointer
+ * if (str.equals("foo")) {
+ * throw new IllegalArgumentException();
+ * } else {
+ * throw new RuntimeException();
+ * }
+ * }
+ * </pre>
+ */
+ public static class StackMapForThrowingInitializerTest$MainDump implements Opcodes {
+
+ public static byte[] dump() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ FieldVisitor fieldVisitor;
+ MethodVisitor methodVisitor;
+
+ classWriter.visit(
+ V1_8,
+ ACC_PUBLIC,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ null,
+ "java/lang/Object",
+ null);
+
+ {
+ fieldVisitor =
+ classWriter.visitField(
+ ACC_PRIVATE | ACC_FINAL, "str", "Ljava/lang/String;", null, null);
+ fieldVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ methodVisitor.visitFieldInsn(
+ PUTFIELD,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "str",
+ "Ljava/lang/String;");
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 2);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC, "<init>", "(Ljava/lang/Object;Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitVarInsn(ASTORE, 0);
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitLdcInsn("foo");
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
+ Label label0 = new Label();
+ methodVisitor.visitJumpInsn(IFNE, label0);
+ methodVisitor.visitFrame(Opcodes.F_FULL, 0, new Object[] {}, 0, new Object[] {});
+ methodVisitor.visitTypeInsn(NEW, "java/lang/RuntimeException");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "()V", false);
+ methodVisitor.visitInsn(ATHROW);
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitFrame(Opcodes.F_FULL, 0, new Object[] {}, 0, new Object[] {});
+ methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false);
+ methodVisitor.visitInsn(ATHROW);
+ methodVisitor.visitMaxs(2, 3);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(ARRAYLENGTH);
+ Label label0 = new Label();
+ methodVisitor.visitJumpInsn(IFNE, label0);
+ methodVisitor.visitTypeInsn(
+ NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitInsn(ACONST_NULL);
+ methodVisitor.visitLdcInsn("foo");
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;)V",
+ false);
+ Label label1 = new Label();
+ methodVisitor.visitJumpInsn(GOTO, label1);
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/io/PrintStream"});
+ methodVisitor.visitTypeInsn(
+ NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitLdcInsn(
+ Type.getType("Lcom/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main;"));
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitInsn(AALOAD);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;)V",
+ false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "toString",
+ "()Ljava/lang/String;",
+ false);
+ methodVisitor.visitLabel(label1);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 1,
+ new Object[] {"[Ljava/lang/String;"},
+ 2,
+ new Object[] {"java/io/PrintStream", "java/lang/Object"});
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(6, 1);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/StackMapForThrowingInitializerTest.java b/src/test/java/com/android/tools/r8/cf/StackMapForThrowingInitializerTest.java
new file mode 100644
index 0000000..bea206e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/StackMapForThrowingInitializerTest.java
@@ -0,0 +1,311 @@
+// Copyright (c) 2021, 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.cf;
+
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+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;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** This is a reproduction of b/183285081 */
+@RunWith(Parameterized.class)
+public class StackMapForThrowingInitializerTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final String[] EXPECTED = new String[] {"Hello World"};
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ public StackMapForThrowingInitializerTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+ .run(parameters.getRuntime(), Main.class, EXPECTED)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class, EXPECTED)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+ .addKeepClassAndMembersRules(Main.class)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class, EXPECTED)
+ // TODO(b/183285081): Should not have verification errors.
+ .assertFailureWithErrorThatMatches(
+ containsString("java.lang.VerifyError: Inconsistent stackmap frames at branch target"));
+ }
+
+ @NeverClassInline
+ public static class Main {
+
+ private final String str;
+
+ @NeverInline
+ public Main(String str) {
+ this.str = str;
+ }
+
+ public Main(Object obj, String str) {
+ this(str);
+ if (str.equals("foo")) {
+ throw new IllegalArgumentException();
+ }
+ if (obj == null) {
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return str;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(
+ args.length == 0 ? new Main(null, "foo") : new Main(Main.class, args[0]).toString());
+ }
+ }
+
+ /**
+ * The dump below is just the ASM code of the class above where:
+ *
+ * <pre>
+ * public Main(Object obj, String str) {
+ * this(str);
+ * if (str.equals("foo")) {
+ * throw new IllegalArgumentException();
+ * }
+ * if (obj == null) {
+ * throw new RuntimeException();
+ * }
+ * }
+ * </pre>
+ *
+ * is changed to have the initializer call in the bottom:
+ *
+ * <pre>
+ * public Main(Object obj, String str) {
+ * if (str.equals("foo")) {
+ * throw new IllegalArgumentException();
+ * }
+ * if (obj == null) {
+ * throw new RuntimeException();
+ * }
+ * this(str);
+ * }
+ * </pre>
+ */
+ public static class StackMapForThrowingInitializerTest$MainDump implements Opcodes {
+
+ public static byte[] dump() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ FieldVisitor fieldVisitor;
+ MethodVisitor methodVisitor;
+ AnnotationVisitor annotationVisitor0;
+
+ classWriter.visit(
+ V1_8,
+ ACC_PUBLIC | ACC_SUPER,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ null,
+ "java/lang/Object",
+ null);
+
+ {
+ annotationVisitor0 =
+ classWriter.visitAnnotation("Lcom/android/tools/r8/NeverClassInline;", false);
+ annotationVisitor0.visitEnd();
+ }
+ classWriter.visitInnerClass(
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest",
+ "Main",
+ ACC_PUBLIC | ACC_STATIC);
+
+ {
+ fieldVisitor =
+ classWriter.visitField(
+ ACC_PRIVATE | ACC_FINAL, "str", "Ljava/lang/String;", null, null);
+ fieldVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, null);
+ {
+ annotationVisitor0 =
+ methodVisitor.visitAnnotation("Lcom/android/tools/r8/NeverInline;", false);
+ annotationVisitor0.visitEnd();
+ }
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ methodVisitor.visitFieldInsn(
+ PUTFIELD,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "str",
+ "Ljava/lang/String;");
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 2);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC, "<init>", "(Ljava/lang/Object;Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitLdcInsn("foo");
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
+ Label label0 = new Label();
+ methodVisitor.visitJumpInsn(IFEQ, label0);
+ methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false);
+ methodVisitor.visitInsn(ATHROW);
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 3,
+ new Object[] {Opcodes.UNINITIALIZED_THIS, "java/lang/Object", "java/lang/String"},
+ 0,
+ new Object[] {});
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ Label label1 = new Label();
+ methodVisitor.visitJumpInsn(IFNONNULL, label1);
+ methodVisitor.visitTypeInsn(NEW, "java/lang/RuntimeException");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "()V", false);
+ methodVisitor.visitInsn(ATHROW);
+ methodVisitor.visitLabel(label1);
+ methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "<init>",
+ "(Ljava/lang/String;)V",
+ false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 3);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitFieldInsn(
+ GETFIELD,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "str",
+ "Ljava/lang/String;");
+ methodVisitor.visitInsn(ARETURN);
+ methodVisitor.visitMaxs(1, 1);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(ARRAYLENGTH);
+ Label label0 = new Label();
+ methodVisitor.visitJumpInsn(IFNE, label0);
+ methodVisitor.visitTypeInsn(
+ NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitInsn(ACONST_NULL);
+ methodVisitor.visitLdcInsn("foo");
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;)V",
+ false);
+ Label label1 = new Label();
+ methodVisitor.visitJumpInsn(GOTO, label1);
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/io/PrintStream"});
+ methodVisitor.visitTypeInsn(
+ NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitLdcInsn(
+ Type.getType("Lcom/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main;"));
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitInsn(AALOAD);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;)V",
+ false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+ "toString",
+ "()Ljava/lang/String;",
+ false);
+ methodVisitor.visitLabel(label1);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 1,
+ new Object[] {"[Ljava/lang/String;"},
+ 2,
+ new Object[] {"java/io/PrintStream", "java/lang/Object"});
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(6, 1);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
index e9d9d79..67db3d7 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -80,7 +80,9 @@
.assertWarningMessageThatMatches(containsString("is not supported by this compiler"))
.run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
.assertFailureWithErrorThatMatches(
- containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
+ containsString(
+ "java.lang.NoSuchMethodError: No static method"
+ + " parseInt(Ljava/lang/CharSequence;III)I"));
}
@Test
@@ -90,7 +92,9 @@
.setMinApi(AndroidApiLevel.magicApiLevelUsedByAndroidPlatformBuild)
.run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
.assertFailureWithErrorThatMatches(
- containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
+ containsString(
+ "java.lang.NoSuchMethodError: No static method"
+ + " parseInt(Ljava/lang/CharSequence;III)I"));
}
// Test class for using: List List.of()
@@ -141,9 +145,9 @@
.transformMethodInsnInMethod(
"main",
(opcode, owner, name, descriptor, isInterface, visitor) -> {
- if (name.equals("Math_multiplyExact")) {
+ if (name.equals("Integer_parseInt")) {
visitor.visitMethodInsn(
- opcode, "java/lang/Math", "multiplyExact", descriptor, isInterface);
+ opcode, "java/lang/Integer", "parseInt", descriptor, isInterface);
} else {
visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
@@ -152,12 +156,12 @@
}
static class TestMathMultiplyExactLongInt {
- public static long Math_multiplyExact(long l, int i) {
+ public static int Integer_parseInt(CharSequence s, int beginIndex, int endIndex, int radix) {
throw null;
}
public static void main(String[] args) {
- System.out.println(Math_multiplyExact(2L, 2));
+ System.out.println(Integer_parseInt("4", 0, 1, 10));
}
}
}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
index b968127..92f5365 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
@@ -117,7 +117,7 @@
if (isR8
&& parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1)) {
- // TODO(b/1822553980: This should be EXPECTED.
+ // TODO(b/182255398): This should be EXPECTED.
result.assertSuccessWithOutput(EXPECTED_R8);
return;
}
diff --git a/src/test/java/com/android/tools/r8/ir/DebugLocalStackMapTest.java b/src/test/java/com/android/tools/r8/ir/DebugLocalStackMapTest.java
new file mode 100644
index 0000000..ddda774
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/DebugLocalStackMapTest.java
@@ -0,0 +1,697 @@
+// Copyright (c) 2021, 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;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
+
+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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class DebugLocalStackMapTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ }
+
+ public DebugLocalStackMapTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testInvalidDebugLocals() throws Exception {
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(TestKtDump.dump())
+ .setMinApi(parameters.getApiLevel())
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertInfosMatch(
+ ImmutableList.of(
+ diagnosticMessage(
+ containsString("Stripped invalid locals information from 1 method")),
+ diagnosticMessage(
+ allOf(
+ containsString(
+ "java.lang.Object"
+ + " TestKt.suspendHere(kotlin.coroutines.Continuation)"),
+ containsString(
+ "Information in locals-table is invalid with respect to the"
+ + " stack map table"))),
+ diagnosticMessage(
+ containsString(
+ "Some warnings are typically a sign of using an outdated Java"
+ + " toolchain"))));
+ });
+ }
+
+ public static class TestKtDump implements Opcodes {
+
+ public static byte[] dump() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ MethodVisitor methodVisitor;
+ AnnotationVisitor annotationVisitor0;
+
+ classWriter.visit(
+ V1_8, ACC_PUBLIC | ACC_FINAL | ACC_SUPER, "TestKt", null, "java/lang/Object", null);
+
+ classWriter.visitSource(
+ "test.kt",
+ "SMAP\n"
+ + "test.kt\n"
+ + "Kotlin\n"
+ + "*S Kotlin\n"
+ + "*F\n"
+ + "+ 1 test.kt\n"
+ + "TestKt\n"
+ + "*L\n"
+ + "1#1,17:1\n"
+ + "4#1,4:18\n"
+ + "10#1:22\n"
+ + "4#1,4:23\n"
+ + "*S KotlinDebug\n"
+ + "*F\n"
+ + "+ 1 test.kt\n"
+ + "TestKt\n"
+ + "*L\n"
+ + "10#1:18,4\n"
+ + "12#1:22\n"
+ + "12#1:23,4\n"
+ + "*E\n");
+
+ {
+ annotationVisitor0 = classWriter.visitAnnotation("Lkotlin/Metadata;", true);
+ annotationVisitor0.visit("mv", new int[] {1, 5, 0});
+ annotationVisitor0.visit("k", new Integer(2));
+ annotationVisitor0.visit("xi", new Integer(50));
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d1");
+ annotationVisitor1.visit(
+ null,
+ "\u0000\u0012\n"
+ + "\u0000\n"
+ + "\u0002\u0010\u0002\n"
+ + "\u0002\u0008\u0002\n"
+ + "\u0002\u0010\u000e\n"
+ + "\u0002\u0008\u0004\u001a\u0011\u0010\u0000\u001a\u00020\u0001H\u0086@\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0002\u001a\u0011\u0010\u0003\u001a\u00020\u0004H\u0086@\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0002\u001a\u0011\u0010\u0005\u001a\u00020\u0004H\u0086H\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0002\u001a\u0019\u0010\u0006\u001a\u00020\u00042\u0006\u0010\u0007\u001a\u00020\u0004H\u0086H\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0008\u0082\u0002\u0004\n"
+ + "\u0002\u0008\u0019");
+ annotationVisitor1.visitEnd();
+ }
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d2");
+ annotationVisitor1.visit(null, "main");
+ annotationVisitor1.visit(null, "");
+ annotationVisitor1.visit(null, "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;");
+ annotationVisitor1.visit(null, "mainSuspend");
+ annotationVisitor1.visit(null, "");
+ annotationVisitor1.visit(null, "suspendHere");
+ annotationVisitor1.visit(null, "suspendThere");
+ annotationVisitor1.visit(null, "v");
+ annotationVisitor1.visit(
+ null, "(Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;");
+ annotationVisitor1.visitEnd();
+ }
+ annotationVisitor0.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_FINAL | ACC_STATIC,
+ "suspendHere",
+ "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;",
+ "(Lkotlin/coroutines/Continuation<-Ljava/lang/String;>;)Ljava/lang/Object;",
+ null);
+ {
+ annotationVisitor0 =
+ methodVisitor.visitAnnotation("Lorg/jetbrains/annotations/Nullable;", false);
+ annotationVisitor0.visitEnd();
+ }
+ methodVisitor.visitAnnotableParameterCount(1, false);
+ {
+ annotationVisitor0 =
+ methodVisitor.visitParameterAnnotation(
+ 0, "Lorg/jetbrains/annotations/NotNull;", false);
+ annotationVisitor0.visitEnd();
+ }
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitTypeInsn(INSTANCEOF, "TestKt$suspendHere$1");
+ Label label0 = new Label();
+ methodVisitor.visitJumpInsn(IFEQ, label0);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitTypeInsn(CHECKCAST, "TestKt$suspendHere$1");
+ methodVisitor.visitVarInsn(ASTORE, 13);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "label", "I");
+ methodVisitor.visitLdcInsn(new Integer(-2147483648));
+ methodVisitor.visitInsn(IAND);
+ methodVisitor.visitJumpInsn(IFEQ, label0);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "label", "I");
+ methodVisitor.visitLdcInsn(new Integer(-2147483648));
+ methodVisitor.visitInsn(ISUB);
+ methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "label", "I");
+ Label label1 = new Label();
+ methodVisitor.visitJumpInsn(GOTO, label1);
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ methodVisitor.visitTypeInsn(NEW, "TestKt$suspendHere$1");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "TestKt$suspendHere$1",
+ "<init>",
+ "(Lkotlin/coroutines/Continuation;)V",
+ false);
+ methodVisitor.visitVarInsn(ASTORE, 13);
+ methodVisitor.visitLabel(label1);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 14,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "TestKt$suspendHere$1"
+ },
+ 0,
+ new Object[] {});
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitFieldInsn(
+ GETFIELD, "TestKt$suspendHere$1", "result", "Ljava/lang/Object;");
+ methodVisitor.visitVarInsn(ASTORE, 12);
+ Label label2 = new Label();
+ methodVisitor.visitLabel(label2);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED",
+ "()Ljava/lang/Object;",
+ false);
+ Label label3 = new Label();
+ methodVisitor.visitLabel(label3);
+ methodVisitor.visitLineNumber(10, label3);
+ methodVisitor.visitVarInsn(ASTORE, 14);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "label", "I");
+ Label label4 = new Label();
+ Label label5 = new Label();
+ Label label6 = new Label();
+ Label label7 = new Label();
+ methodVisitor.visitTableSwitchInsn(0, 2, label7, new Label[] {label4, label5, label6});
+ methodVisitor.visitLabel(label4);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 0,
+ new Object[] {});
+ methodVisitor.visitVarInsn(ALOAD, 12);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 1);
+ Label label8 = new Label();
+ methodVisitor.visitLabel(label8);
+ methodVisitor.visitLineNumber(10, label8);
+ methodVisitor.visitLdcInsn("O");
+ methodVisitor.visitVarInsn(ASTORE, 2);
+ Label label9 = new Label();
+ methodVisitor.visitLabel(label9);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 3);
+ Label label10 = new Label();
+ methodVisitor.visitLabel(label10);
+ methodVisitor.visitLineNumber(18, label10);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitInsn(ICONST_1);
+ methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "label", "I");
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+ methodVisitor.visitVarInsn(ASTORE, 4);
+ Label label11 = new Label();
+ methodVisitor.visitLabel(label11);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 5);
+ Label label12 = new Label();
+ methodVisitor.visitLabel(label12);
+ methodVisitor.visitLineNumber(19, label12);
+ methodVisitor.visitVarInsn(ALOAD, 4);
+ methodVisitor.visitVarInsn(ASTORE, 6);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 7);
+ methodVisitor.visitVarInsn(ALOAD, 6);
+ methodVisitor.visitFieldInsn(
+ GETSTATIC, "kotlin/Result", "Companion", "Lkotlin/Result$Companion;");
+ methodVisitor.visitVarInsn(ASTORE, 8);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 9);
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/Result",
+ "constructor-impl",
+ "(Ljava/lang/Object;)Ljava/lang/Object;",
+ false);
+ methodVisitor.visitMethodInsn(
+ INVOKEINTERFACE,
+ "kotlin/coroutines/Continuation",
+ "resumeWith",
+ "(Ljava/lang/Object;)V",
+ true);
+ Label label13 = new Label();
+ methodVisitor.visitLabel(label13);
+ methodVisitor.visitLineNumber(20, label13);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED",
+ "()Ljava/lang/Object;",
+ false);
+ Label label14 = new Label();
+ methodVisitor.visitLabel(label14);
+ methodVisitor.visitLineNumber(18, label14);
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED",
+ "()Ljava/lang/Object;",
+ false);
+ Label label15 = new Label();
+ methodVisitor.visitJumpInsn(IF_ACMPNE, label15);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/coroutines/jvm/internal/DebugProbesKt",
+ "probeCoroutineSuspended",
+ "(Lkotlin/coroutines/Continuation;)V",
+ false);
+ methodVisitor.visitLabel(label15);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "java/lang/String",
+ Opcodes.INTEGER,
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "kotlin/Result$Companion",
+ Opcodes.INTEGER,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 1,
+ new Object[] {"java/lang/Object"});
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitVarInsn(ALOAD, 14);
+ Label label16 = new Label();
+ methodVisitor.visitJumpInsn(IF_ACMPNE, label16);
+ Label label17 = new Label();
+ methodVisitor.visitLabel(label17);
+ methodVisitor.visitLineNumber(10, label17);
+ methodVisitor.visitVarInsn(ALOAD, 14);
+ methodVisitor.visitInsn(ARETURN);
+ methodVisitor.visitLabel(label5);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 0,
+ new Object[] {});
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 1);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 3);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+ methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+ methodVisitor.visitVarInsn(ASTORE, 2);
+ methodVisitor.visitVarInsn(ALOAD, 12);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false);
+ methodVisitor.visitVarInsn(ALOAD, 12);
+ methodVisitor.visitLabel(label16);
+ methodVisitor.visitLineNumber(21, label16);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "java/lang/String",
+ Opcodes.INTEGER,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 1,
+ new Object[] {"java/lang/Object"});
+ methodVisitor.visitInsn(NOP);
+ Label label18 = new Label();
+ methodVisitor.visitLabel(label18);
+ methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+ Label label19 = new Label();
+ methodVisitor.visitLabel(label19);
+ methodVisitor.visitLineNumber(10, label19);
+ methodVisitor.visitLdcInsn("K");
+ methodVisitor.visitVarInsn(ASTORE, 2);
+ methodVisitor.visitVarInsn(ASTORE, 10);
+ Label label20 = new Label();
+ methodVisitor.visitLabel(label20);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 3);
+ Label label21 = new Label();
+ methodVisitor.visitLabel(label21);
+ methodVisitor.visitLineNumber(18, label21);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitVarInsn(ALOAD, 10);
+ methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "L$1", "Ljava/lang/Object;");
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitInsn(ICONST_2);
+ methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "label", "I");
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+ methodVisitor.visitVarInsn(ASTORE, 4);
+ Label label22 = new Label();
+ methodVisitor.visitLabel(label22);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 5);
+ Label label23 = new Label();
+ methodVisitor.visitLabel(label23);
+ methodVisitor.visitLineNumber(19, label23);
+ methodVisitor.visitVarInsn(ALOAD, 4);
+ methodVisitor.visitVarInsn(ASTORE, 6);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 7);
+ methodVisitor.visitVarInsn(ALOAD, 6);
+ methodVisitor.visitFieldInsn(
+ GETSTATIC, "kotlin/Result", "Companion", "Lkotlin/Result$Companion;");
+ methodVisitor.visitVarInsn(ASTORE, 8);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 9);
+ methodVisitor.visitVarInsn(ALOAD, 2);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/Result",
+ "constructor-impl",
+ "(Ljava/lang/Object;)Ljava/lang/Object;",
+ false);
+ methodVisitor.visitMethodInsn(
+ INVOKEINTERFACE,
+ "kotlin/coroutines/Continuation",
+ "resumeWith",
+ "(Ljava/lang/Object;)V",
+ true);
+ Label label24 = new Label();
+ methodVisitor.visitLabel(label24);
+ methodVisitor.visitLineNumber(20, label24);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED",
+ "()Ljava/lang/Object;",
+ false);
+ Label label25 = new Label();
+ methodVisitor.visitLabel(label25);
+ methodVisitor.visitLineNumber(18, label25);
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED",
+ "()Ljava/lang/Object;",
+ false);
+ Label label26 = new Label();
+ methodVisitor.visitJumpInsn(IF_ACMPNE, label26);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/coroutines/jvm/internal/DebugProbesKt",
+ "probeCoroutineSuspended",
+ "(Lkotlin/coroutines/Continuation;)V",
+ false);
+ methodVisitor.visitLabel(label26);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "java/lang/String",
+ Opcodes.INTEGER,
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "kotlin/Result$Companion",
+ Opcodes.INTEGER,
+ "java/lang/String",
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 1,
+ new Object[] {"java/lang/Object"});
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitVarInsn(ALOAD, 14);
+ Label label27 = new Label();
+ methodVisitor.visitJumpInsn(IF_ACMPNE, label27);
+ Label label28 = new Label();
+ methodVisitor.visitLabel(label28);
+ methodVisitor.visitLineNumber(10, label28);
+ methodVisitor.visitVarInsn(ALOAD, 14);
+ methodVisitor.visitInsn(ARETURN);
+ methodVisitor.visitLabel(label6);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 0,
+ new Object[] {});
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 1);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 3);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "L$1", "Ljava/lang/Object;");
+ methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+ methodVisitor.visitVarInsn(ASTORE, 10);
+ methodVisitor.visitVarInsn(ALOAD, 13);
+ methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+ methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+ methodVisitor.visitVarInsn(ASTORE, 2);
+ methodVisitor.visitVarInsn(ALOAD, 12);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false);
+ methodVisitor.visitVarInsn(ALOAD, 12);
+ methodVisitor.visitLabel(label27);
+ methodVisitor.visitLineNumber(21, label27);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.INTEGER,
+ "java/lang/String",
+ Opcodes.INTEGER,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "java/lang/String",
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 1,
+ new Object[] {"java/lang/Object"});
+ methodVisitor.visitInsn(NOP);
+ Label label29 = new Label();
+ methodVisitor.visitLabel(label29);
+ methodVisitor.visitVarInsn(ASTORE, 11);
+ methodVisitor.visitVarInsn(ALOAD, 10);
+ methodVisitor.visitVarInsn(ALOAD, 11);
+ Label label30 = new Label();
+ methodVisitor.visitLabel(label30);
+ methodVisitor.visitLineNumber(10, label30);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/jvm/internal/Intrinsics",
+ "stringPlus",
+ "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;",
+ false);
+ methodVisitor.visitInsn(ARETURN);
+ methodVisitor.visitLabel(label7);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 15,
+ new Object[] {
+ "kotlin/coroutines/Continuation",
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ Opcodes.TOP,
+ "java/lang/Object",
+ "TestKt$suspendHere$1",
+ "java/lang/Object"
+ },
+ 0,
+ new Object[] {});
+ methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalStateException");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "java/lang/IllegalStateException",
+ "<init>",
+ "(Ljava/lang/String;)V",
+ false);
+ methodVisitor.visitInsn(ATHROW);
+ methodVisitor.visitLocalVariable("v$iv", "Ljava/lang/String;", null, label9, label15, 2);
+ methodVisitor.visitLocalVariable("v$iv", "Ljava/lang/String;", null, label20, label26, 2);
+ methodVisitor.visitLocalVariable(
+ "x$iv", "Lkotlin/coroutines/Continuation;", null, label11, label14, 4);
+ methodVisitor.visitLocalVariable(
+ "x$iv", "Lkotlin/coroutines/Continuation;", null, label22, label25, 4);
+ methodVisitor.visitLocalVariable(
+ "$i$a$-suspendCoroutineUninterceptedOrReturn-TestKt$suspendThere$2$iv",
+ "I",
+ null,
+ label12,
+ label14,
+ 5);
+ methodVisitor.visitLocalVariable("$i$f$suspendThere", "I", null, label10, label18, 3);
+ methodVisitor.visitLocalVariable(
+ "$i$a$-suspendCoroutineUninterceptedOrReturn-TestKt$suspendThere$2$iv",
+ "I",
+ null,
+ label23,
+ label25,
+ 5);
+ methodVisitor.visitLocalVariable("$i$f$suspendThere", "I", null, label21, label29, 3);
+ methodVisitor.visitLocalVariable("$i$f$suspendHere", "I", null, label8, label7, 1);
+ methodVisitor.visitLocalVariable(
+ "$continuation", "Lkotlin/coroutines/Continuation;", null, label1, label7, 13);
+ methodVisitor.visitLocalVariable("$result", "Ljava/lang/Object;", null, label2, label7, 12);
+ methodVisitor.visitMaxs(3, 15);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseWithNoShrinkingTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseWithNoShrinkingTest.java
new file mode 100644
index 0000000..b9d0ef6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseWithNoShrinkingTest.java
@@ -0,0 +1,77 @@
+// 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.missingclasses;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class MissingClassReferencedFromThrowsClauseWithNoShrinkingTest
+ extends MissingClassesTestBase {
+
+ private static final String NEW_A_DESCRIPTOR = "Lfoo/a;";
+ private static final String NEW_B_DESCRIPTOR = "Lfoo/b;";
+
+ private static final MissingDefinitionContext referencedFrom =
+ MissingDefinitionMethodContextImpl.builder()
+ .setMethodContext(
+ Reference.method(
+ Reference.classFromDescriptor("Lfoo/a;"), "foo", ImmutableList.of(), null))
+ .setOrigin(Origin.unknown())
+ .build();
+
+ public MissingClassReferencedFromThrowsClauseWithNoShrinkingTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Test(expected = CompilationFailedException.class)
+ public void testNoShrinking() throws Exception {
+ compileWithExpectedDiagnostics(
+ Main.class,
+ diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+ b -> {
+ b.addProgramClassFileData(
+ transformer(A.class)
+ .setClassDescriptor(NEW_A_DESCRIPTOR)
+ .removeInnerClasses()
+ .transform(),
+ transformer(B.class)
+ .setClassDescriptor(NEW_B_DESCRIPTOR)
+ .removeInnerClasses()
+ .replaceClassDescriptorInMethodInstructions(descriptor(A.class), NEW_A_DESCRIPTOR)
+ .transform());
+ b.enableInliningAnnotations();
+ b.addKeepClassAndMembersRules(DescriptorUtils.descriptorToJavaType(NEW_A_DESCRIPTOR));
+ b.noTreeShaking();
+ });
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {}
+ }
+
+ public static class /* will be: foo.A */ A {
+
+ @NeverInline
+ public static void foo() throws MissingClass {
+ System.out.println("Hello World");
+ }
+ }
+
+ public static class /* will be: foo.B */ B {
+
+ public static void callFoo() {
+ A.foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/MapReaderVersionTest.java b/src/test/java/com/android/tools/r8/naming/MapReaderVersionTest.java
new file mode 100644
index 0000000..36916ad
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MapReaderVersionTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, 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.naming;
+
+import static junit.framework.TestCase.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import org.junit.Assert;
+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 MapReaderVersionTest extends TestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public MapReaderVersionTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ @Test
+ public void testNoVersion() throws IOException {
+ ClassNameMapper mapper =
+ ClassNameMapper.mapperFromString(
+ StringUtils.joinLines(
+ "pkg.Foo -> a.a:", "# { id: \"com.android.tools.r8.synthesized\" }"));
+ assertMapping("a.a", "pkg.Foo", false, mapper);
+ }
+
+ @Test
+ public void testExperimentalVersion() throws IOException {
+ ClassNameMapper mapper =
+ ClassNameMapper.mapperFromString(
+ StringUtils.joinLines(
+ "# { id: 'com.android.tools.r8.metainf', map-version: 'experimental' }",
+ "pkg.Foo -> a.a:",
+ "# { id: 'com.android.tools.r8.synthesized' }"));
+ assertMapping("a.a", "pkg.Foo", true, mapper);
+ }
+
+ @Test
+ public void testConcatMapFiles() throws IOException {
+ ClassNameMapper mapper =
+ ClassNameMapper.mapperFromString(
+ StringUtils.joinLines(
+ // Default map-version is none.
+ "pkg.Foo -> a.a:",
+ "# { id: 'com.android.tools.r8.synthesized' }",
+ // Section with map-version experimental.
+ "# { id: 'com.android.tools.r8.metainf', map-version: 'experimental' }",
+ "pkg.Bar -> a.b:",
+ "# { id: 'com.android.tools.r8.synthesized' }",
+ // Section reverting map-version back to none (to support tooling that
+ // concatenates).
+ "# { id: 'com.android.tools.r8.metainf', map-version: 'none' }",
+ "pkg.Baz -> a.c:",
+ "# { id: 'com.android.tools.r8.synthesized' }"));
+ assertMapping("a.a", "pkg.Foo", false, mapper);
+ assertMapping("a.b", "pkg.Bar", true, mapper);
+ assertMapping("a.c", "pkg.Baz", false, mapper);
+ }
+
+ private void assertMapping(
+ String finalName, String originalName, boolean isSynthesized, ClassNameMapper mapper) {
+ ClassNamingForNameMapper naming = mapper.getClassNaming(finalName);
+ assertEquals(originalName, naming.originalName);
+ Assert.assertEquals(isSynthesized, isCompilerSynthesized(naming));
+ }
+
+ private boolean isCompilerSynthesized(ClassNamingForNameMapper naming) {
+ return naming.getAdditionalMappings().stream()
+ .anyMatch(MappingInformation::isCompilerSynthesizedMappingInformation);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java b/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
index 8b68bd2..6c7156d 100644
--- a/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
@@ -7,37 +7,40 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticPosition;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static com.android.tools.r8.PositionMatcher.positionLine;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
-import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.core.StringContains.containsString;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
-import java.util.List;
-import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
-public class ProguardMapReaderArgumentsTest {
+@RunWith(Parameterized.class)
+public class ProguardMapReaderArgumentsTest extends TestBase {
- private Reporter reporter;
- private TestDiagnosticMessagesImpl testDiagnosticMessages;
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
- @Before
- public void setUp() {
- testDiagnosticMessages = new TestDiagnosticMessagesImpl();
- reporter = new Reporter(testDiagnosticMessages);
+ public ProguardMapReaderArgumentsTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
}
@Test
public void testMethodCanParseMemberComments() throws IOException {
+ TestDiagnosticMessagesImpl testDiagnosticMessages = new TestDiagnosticMessagesImpl();
+ Reporter reporter = new Reporter(testDiagnosticMessages);
String mapWithArgumentRemovalInformation =
StringUtils.join(
"\n",
@@ -69,158 +72,4 @@
diagnosticPosition(positionLine(8)))))
.assertAllInfosMatch(diagnosticType(MappingInformationDiagnostics.class));
}
-
- @Test
- public void testMethodWillReportWhenParsingArgumentsChangedMemberComments() throws IOException {
- String mapWithArgumentRemovalInformation =
- StringUtils.join(
- "\n",
- "android.constraint.Placeholder -> a.b.b.f:",
- "# Just a comment", // Regular comment
- " int mContentId -> b",
- // Valid JSON but missing signature
- "# { 'id': 'methodSignatureChanged', "
- + "'signature': ['void', 'updatePreLayout', 'android.constraint.Layout'],"
- + "'returnType': [], 'receiver': true, 'params': []}",
- " 147:161:void updatePreLayout(android.constraint.Layout) -> a",
- // Valid JSON but not an argumentsChanged object
- "# { 'id': 'methodSignatureChanged', "
- + "'signature': ['void', 'updatePreLayout', 'android.constraint.Layout'],"
- + "'returnType': [], 'receiver': true, 'params': []}",
- " 147:161:void updatePreLayout(android.constraint.Layout) -> a",
- // Valid JSON but not an arguments_changed object.
- "# { 'id': 'methodSignatureChanged', "
- + "'signature': ['void','updatePreLayout','android.constraint.Layout'],"
- + "'returnType': 'foo', 'receiver': 1, 'params': 'foo' }",
- " 194:204:void updatePostMeasure(android.constraint.Layout) -> a")
- .replace("'", "\"");
- ClassNameMapper cnm =
- ClassNameMapper.mapperFromString(mapWithArgumentRemovalInformation, reporter);
- ClassNamingForNameMapper classNaming = cnm.getClassNaming("a.b.b.f");
- assertNotNull(classNaming);
- testDiagnosticMessages.assertOnlyInfos();
- testDiagnosticMessages
- .assertInfosMatch(
- ImmutableList.of(
- allOf(
- diagnosticMessage(containsString("Could not decode")),
- diagnosticPosition(positionLine(4))),
- allOf(
- diagnosticMessage(containsString("Could not decode")),
- diagnosticPosition(positionLine(6))),
- allOf(
- diagnosticMessage(containsString("Could not decode")),
- diagnosticPosition(positionLine(8)))))
- .assertAllInfosMatch(diagnosticType(MappingInformationDiagnostics.class));
- }
-
- @Test
- public void testMethodCanParseArgumentRemoval() throws IOException {
- String mapWithArgumentRemovalInformation =
- StringUtils.lines(
- "android.constraint.Placeholder -> a.b.b.f:",
- " int mContentId -> b",
- "# { 'id': 'methodSignatureChanged',"
- + "'signature': ["
- + "'void','updatePreLayout','android.constraint.Layout','String','int'],"
- + " 'returnType': 'void', 'receiver': true, 'params':[[1],[2]]}",
- " 147:161:void updatePreLayout(android.constraint.Layout,String,int) -> a",
- "# {'id':'methodSignatureChanged',"
- + "'signature': ["
- + "'void','updatePreMeasure','android.constraint.Layout','String','int'],"
- + "'returnType': 'void', 'receiver': true, 'params':[[3]]}",
- " 162:173:void updatePreMeasure(android.constraint.Layout,String,int) -> a",
- " 194:204:void updatePostMeasure(android.constraint.Layout,String,int) -> a");
- ClassNameMapper cnm = ClassNameMapper.mapperFromString(mapWithArgumentRemovalInformation);
- ClassNamingForNameMapper classNaming = cnm.getClassNaming("a.b.b.f");
- assertNotNull(classNaming);
-
- List<MemberNaming> members = classNaming.lookupByOriginalName("mContentId");
- assertFalse(members.isEmpty());
- MemberNaming fieldContentId = members.get(0);
- assertNotNull(fieldContentId);
- assertTrue(!fieldContentId.isMethodNaming());
-
- members = classNaming.lookupByOriginalName("updatePreLayout");
- assertFalse(members.isEmpty());
- MemberNaming updatePreLayout = members.get(0);
- assertNotNull(updatePreLayout);
- assertTrue(updatePreLayout.isMethodNaming());
- MethodSignature renamedPreLayout = (MethodSignature) updatePreLayout.getRenamedSignature();
- assertEquals(1, renamedPreLayout.parameters.length);
- assertEquals("int", renamedPreLayout.parameters[0]);
-
- members = classNaming.lookupByOriginalName("updatePreMeasure");
- assertFalse(members.isEmpty());
- MemberNaming updatePreMeasure = members.get(0);
- assertNotNull(updatePreMeasure);
- assertTrue(updatePreMeasure.isMethodNaming());
- MethodSignature renamedPreMeasure = (MethodSignature) updatePreMeasure.getRenamedSignature();
- assertEquals(2, renamedPreMeasure.parameters.length);
- assertEquals("android.constraint.Layout", renamedPreMeasure.parameters[0]);
- assertEquals("String", renamedPreMeasure.parameters[1]);
-
- members = classNaming.lookupByOriginalName("updatePostMeasure");
- assertFalse(members.isEmpty());
- MemberNaming updatePostMeasure = members.get(0);
- assertNotNull(updatePostMeasure);
- assertTrue(updatePostMeasure.isMethodNaming());
- MethodSignature renamedPostMeasure = (MethodSignature) updatePostMeasure.getRenamedSignature();
- assertEquals(3, renamedPostMeasure.parameters.length);
- }
-
- @Test
- public void testMethodCanParseArgumentChanged() throws IOException {
- String mapWithArgumentRemovalInformation =
- StringUtils.join(
- "\n",
- "android.constraint.Placeholder -> a.b.b.f:",
- "# {'id':'methodSignatureChanged',"
- + "'signature':["
- + "'void','updatePreLayout','android.constraint.Layout','String','float'],"
- + "'returnType': 'void',"
- + "'receiver': true,"
- + "'params':[[1,int],[2,Foo]]}",
- "# {'id':'methodSignatureChanged',"
- + "'signature':["
- + "'void','updatePreMeasure','android.constraint.Layout','String','int'],"
- + "'returnType': 'void', "
- + "'receiver': true, "
- + "'params':[[2,com.baz.Bar],[3]]}",
- " 147:161:void updatePreLayout(android.constraint.Layout,String,float) -> a",
- " 162:173:void updatePreMeasure(android.constraint.Layout,String,int) -> a",
- " 194:204:void updatePostMeasure(android.constraint.Layout,String,int) -> a");
- ClassNameMapper cnm = ClassNameMapper.mapperFromString(mapWithArgumentRemovalInformation);
- ClassNamingForNameMapper classNaming = cnm.getClassNaming("a.b.b.f");
- assertNotNull(classNaming);
-
- List<MemberNaming> members = classNaming.lookupByOriginalName("updatePreLayout");
- assertFalse(members.isEmpty());
- MemberNaming updatePreLayout = members.get(0);
- assertNotNull(updatePreLayout);
- assertTrue(updatePreLayout.isMethodNaming());
- MethodSignature renamedPreLayout = (MethodSignature) updatePreLayout.getRenamedSignature();
- assertEquals(3, renamedPreLayout.parameters.length);
- assertEquals("int", renamedPreLayout.parameters[0]);
- assertEquals("Foo", renamedPreLayout.parameters[1]);
- assertEquals("float", renamedPreLayout.parameters[2]);
-
- members = classNaming.lookupByOriginalName("updatePreMeasure");
- assertFalse(members.isEmpty());
- MemberNaming updatePreMeasure = members.get(0);
- assertNotNull(updatePreMeasure);
- assertTrue(updatePreMeasure.isMethodNaming());
- MethodSignature renamedPreMeasure = (MethodSignature) updatePreMeasure.getRenamedSignature();
- assertEquals(2, renamedPreMeasure.parameters.length);
- assertEquals("android.constraint.Layout", renamedPreMeasure.parameters[0]);
- assertEquals("com.baz.Bar", renamedPreMeasure.parameters[1]);
-
- members = classNaming.lookupByOriginalName("updatePostMeasure");
- assertFalse(members.isEmpty());
- MemberNaming updatePostMeasure = members.get(0);
- assertNotNull(updatePostMeasure);
- assertTrue(updatePostMeasure.isMethodNaming());
- MethodSignature renamedPostMeasure = (MethodSignature) updatePostMeasure.getRenamedSignature();
- assertEquals(3, renamedPostMeasure.parameters.length);
- }
}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
index 41d1c3f..25cbfbe 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -13,14 +13,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.google.common.collect.ImmutableList;
+import java.io.IOException;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,10 +54,34 @@
@Test
public void testReference() throws Exception {
- testForRuntime(parameters)
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
.addInnerClasses(getClass())
.run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+ .apply(this::checkRunResult)
+ .apply(this::checkNoOutputSynthetics)
+ .inspectStackTrace(
+ stackTrace ->
+ assertThat(
+ stackTrace,
+ isSameExceptForFileNameAndLineNumber(
+ StackTrace.builder()
+ .addWithoutFileNameAndLineNumber(Main.class, JAVAC_LAMBDA_METHOD)
+ .addWithoutFileNameAndLineNumber(Main.class, "runIt")
+ .addWithoutFileNameAndLineNumber(Main.class, "main")
+ .build())));
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .internalEnableMappingOutput()
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .enableExperimentalMapFileVersion()
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkRunResult)
+ .apply(this::checkOneOutputSynthetic)
.inspectStackTrace(
stackTrace ->
assertThat(
@@ -63,45 +90,14 @@
StackTrace.builder()
.addWithoutFileNameAndLineNumber(Main.class, JAVAC_LAMBDA_METHOD)
// TODO(b/172014416): Support a D8 mapping and prune the synthetic.
- .applyIf(
- parameters.isDexRuntime(),
- b ->
- b.addWithoutFileNameAndLineNumber(
- SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0),
- "run"))
+ .addWithoutFileNameAndLineNumber(
+ SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0), "run")
.addWithoutFileNameAndLineNumber(Main.class, "runIt")
.addWithoutFileNameAndLineNumber(Main.class, "main")
.build())));
}
@Test
- public void testMappingInformation() throws Exception {
- assumeTrue("R8/CF does not desugar", parameters.isDexRuntime());
- testForR8(parameters.getBackend())
- .addInnerClasses(getClass())
- .addKeepAttributeSourceFile()
- .addKeepAttributeLineNumberTable()
- .noTreeShaking()
- .noMinification()
- .setMinApi(parameters.getApiLevel())
- .run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatMatches(containsString("Hello World!"))
- .inspectFailure(
- inspector -> {
- Collection<ClassReference> inputs =
- ImmutableList.of(classFromClass(MyRunner.class), classFromClass(Main.class));
- for (FoundClassSubject clazz : inspector.allClasses()) {
- if (inputs.contains(clazz.getFinalReference())) {
- assertThat(clazz, not(isCompilerSynthesized()));
- } else {
- assertThat(clazz, isCompilerSynthesized());
- }
- }
- assertEquals(inputs.size() + 1, inspector.allClasses().size());
- });
- }
-
- @Test
public void testEverythingInlined() throws Exception {
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
@@ -110,18 +106,25 @@
.addKeepAttributeLineNumberTable()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+ .apply(this::checkRunResult)
+ .inspectFailure(
+ inspector ->
+ assertEquals(parameters.isCfRuntime() ? 2 : 1, inspector.allClasses().size()))
.inspectStackTrace(
stackTrace -> {
int frames = parameters.isCfRuntime() ? 2 : 1;
checkRawStackTraceFrameCount(stackTrace, frames, "Expected everything to be inlined");
- checkCurrentlyIncorrectStackTrace(stackTrace, JAVAC_LAMBDA_METHOD);
+ checkCurrentlyIncorrectStackTrace(stackTrace);
});
}
@Test
public void testNothingInlined() throws Exception {
+ assumeTrue(
+ "Skip R8/CF for min-api > 1 (R8/CF does not desugar)",
+ parameters.isDexRuntime() || parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
testForR8(parameters.getBackend())
+ .enableExperimentalMapFileVersion()
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addKeepPackageNamesRule(getClass().getPackage())
@@ -130,15 +133,46 @@
.addKeepAttributeLineNumberTable()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+ .apply(this::checkRunResult)
+ .applyIf(
+ parameters.isCfRuntime(), this::checkNoOutputSynthetics, this::checkOneOutputSynthetic)
.inspectStackTrace(
stackTrace -> {
int frames = parameters.isCfRuntime() ? 3 : 5;
checkRawStackTraceFrameCount(stackTrace, frames, "Expected nothing to be inlined");
- checkCurrentlyIncorrectStackTrace(stackTrace, "lambda$main$0");
+ checkCurrentlyIncorrectStackTrace(stackTrace);
});
}
+ private void checkRunResult(SingleTestRunResult<?> runResult) {
+ runResult.assertFailureWithErrorThatMatches(containsString("Hello World!"));
+ }
+
+ private void checkNoOutputSynthetics(SingleTestRunResult<?> runResult) throws IOException {
+ checkOutputSynthetics(runResult, 0);
+ }
+
+ private void checkOneOutputSynthetic(SingleTestRunResult<?> runResult) throws IOException {
+ checkOutputSynthetics(runResult, 1);
+ }
+
+ private void checkOutputSynthetics(SingleTestRunResult<?> runResult, int expectedSyntheticsCount)
+ throws IOException {
+ runResult.inspectFailure(
+ inspector -> {
+ Collection<ClassReference> inputs =
+ ImmutableList.of(classFromClass(MyRunner.class), classFromClass(Main.class));
+ for (FoundClassSubject clazz : inspector.allClasses()) {
+ if (inputs.contains(clazz.getOriginalReference())) {
+ assertThat(clazz, not(isCompilerSynthesized()));
+ } else {
+ assertThat(clazz, isCompilerSynthesized());
+ }
+ }
+ assertEquals(inputs.size() + expectedSyntheticsCount, inspector.allClasses().size());
+ });
+ }
+
private void checkRawStackTraceFrameCount(
StackTrace stackTrace, int expectedFrames, String message) {
int linesFromTest = 0;
@@ -150,12 +184,12 @@
assertEquals(message + stackTrace.getOriginalStderr(), expectedFrames, linesFromTest);
}
- private void checkCurrentlyIncorrectStackTrace(StackTrace stackTrace, String javacLambdaMethod) {
+ private void checkCurrentlyIncorrectStackTrace(StackTrace stackTrace) {
assertThat(
stackTrace,
isSameExceptForFileNameAndLineNumber(
StackTrace.builder()
- .addWithoutFileNameAndLineNumber(Main.class, javacLambdaMethod)
+ .addWithoutFileNameAndLineNumber(Main.class, RetraceLambdaTest.JAVAC_LAMBDA_METHOD)
.applyIf(
parameters.isDexRuntime(),
b ->
diff --git a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
index 5492f54..b0e1ab2 100644
--- a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
+++ b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
@@ -30,9 +30,7 @@
ToolHelper.getFirstSupportedAndroidJar(AndroidApiLevel.K_WATCH), AndroidApiLevel.L);
// All android.jar's for API level L are present.
for (AndroidApiLevel androidApiLevel : AndroidApiLevel.values()) {
- // TODO(b/181356260): Add AndroidJar for S.
- if (androidApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L)
- && androidApiLevel.isLessThan(AndroidApiLevel.S)) {
+ if (androidApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L)) {
checkExpectedAndroidJar(
ToolHelper.getFirstSupportedAndroidJar(androidApiLevel), androidApiLevel);
}
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 1763108..769760b 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
@@ -26,7 +26,6 @@
import com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.NoSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
import com.android.tools.r8.naming.signature.GenericSignatureParser;
@@ -46,7 +45,6 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -419,15 +417,7 @@
if (naming == null) {
return false;
}
- Map<Signature, List<MappingInformation>> additionalMappings = naming.getAdditionalMappings();
- if (additionalMappings == null) {
- return false;
- }
- List<MappingInformation> infos = additionalMappings.get(NoSignature.NO_SIGNATURE);
- if (infos == null) {
- return false;
- }
- for (MappingInformation info : infos) {
+ for (MappingInformation info : naming.getAdditionalMappings()) {
if (info.isCompilerSynthesizedMappingInformation()) {
return true;
}
diff --git a/third_party/android_jar/lib-v31.tar.gz.sha1 b/third_party/android_jar/lib-v31.tar.gz.sha1
new file mode 100644
index 0000000..20eb896
--- /dev/null
+++ b/third_party/android_jar/lib-v31.tar.gz.sha1
@@ -0,0 +1 @@
+758bc25bf1aa97fab86205b0dd5db396f9b129cd
\ No newline at end of file