Add support for tracking original file names in proguard map
Bug: 143337111
Change-Id: I23db313fa7c3c0ef63b1fb2346628e88b46ca44d
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 07948a1..bb772d8 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -609,11 +609,6 @@
}
}
- // Overwrite SourceFile if specified. This step should be done after IR conversion.
- timing.begin("Rename SourceFile");
- new SourceFileRewriter(appViewWithLiveness).run();
- timing.end();
-
// Collect the already pruned types before creating a new app info without liveness.
Set<DexType> prunedTypes = appView.withLiveness().appInfo().getPrunedTypes();
@@ -823,6 +818,11 @@
LineNumberOptimizer.run(appView, application, inputApp, namingLens);
timing.end();
+ // Overwrite SourceFile if specified. This step should be done after IR conversion.
+ timing.begin("Rename SourceFile");
+ new SourceFileRewriter(appView, application).run();
+ timing.end();
+
// If a method filter is present don't produce output since the application is likely partial.
if (options.hasMethodsFilter()) {
System.out.println("Finished compilation with method filter: ");
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 8e6d95c..43a0511 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.naming.ClassNameMapper.MissingFileAction.MISSING_FILE_IS_ERROR;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
@@ -91,15 +92,17 @@
return mapperFromBufferedReader(CharSource.wrap(contents).openBufferedStream(), null);
}
- public static ClassNameMapper mapperFromString(String contents, Reporter reporter)
- throws IOException {
- return mapperFromBufferedReader(CharSource.wrap(contents).openBufferedStream(), reporter);
+ public static ClassNameMapper mapperFromString(
+ String contents, DiagnosticsHandler diagnosticsHandler) throws IOException {
+ return mapperFromBufferedReader(
+ CharSource.wrap(contents).openBufferedStream(), diagnosticsHandler);
}
- private static ClassNameMapper mapperFromBufferedReader(BufferedReader reader, Reporter reporter)
- throws IOException {
+ private static ClassNameMapper mapperFromBufferedReader(
+ BufferedReader reader, DiagnosticsHandler diagnosticsHandler) throws IOException {
try (ProguardMapReader proguardReader =
- new ProguardMapReader(reader, reporter != null ? reporter : new Reporter())) {
+ new ProguardMapReader(
+ reader, diagnosticsHandler != null ? diagnosticsHandler : new Reporter())) {
ClassNameMapper.Builder builder = ClassNameMapper.builder();
proguardReader.parse(builder);
return builder.build();
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNaming.java b/src/main/java/com/android/tools/r8/naming/ClassNaming.java
index d309e78..5a282d0 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNaming.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
import com.android.tools.r8.utils.ThrowingConsumer;
@@ -20,6 +21,11 @@
public abstract Builder addMappingInformation(MappingInformation mappingInformation);
+ public abstract Builder addMappingInformation(
+ MappingInformation mappingInformation,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber);
+
public abstract ClassNaming build();
/** This is an optional method, may be implemented as no-op */
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
index a93c04a..acbb577 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
@@ -83,6 +84,15 @@
}
@Override
+ public ClassNaming.Builder addMappingInformation(
+ MappingInformation mappingInformation,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber) {
+ // Intentionally kept empty until we support additional information with -applymapping.
+ return this;
+ }
+
+ @Override
public ClassNamingForMapApplier build() {
return new ClassNamingForMapApplier(
renamedName, originalName, position, qualifiedMethodMembers, methodMembers, fieldMembers);
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 1d52720..98293ab 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -3,11 +3,15 @@
// 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;
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.naming.MemberNaming.Signature.SignatureKind;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+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.ImmutableMap;
@@ -20,6 +24,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Consumer;
/**
* Stores name information for a class.
@@ -58,13 +63,39 @@
@Override
public ClassNaming.Builder addMappingInformation(MappingInformation mappingInformation) {
+ return addMappingInformation(
+ mappingInformation,
+ other -> {
+ assert false;
+ });
+ }
+
+ @Override
+ public ClassNaming.Builder addMappingInformation(
+ MappingInformation mappingInformation,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber) {
+ return addMappingInformation(
+ mappingInformation,
+ other ->
+ diagnosticsHandler.warning(
+ MappingInformationDiagnostics.notAllowedCombination(
+ originalName, renamedName, mappingInformation, other, lineNumber)));
+ }
+
+ private ClassNaming.Builder addMappingInformation(
+ MappingInformation mappingInformation, Consumer<MappingInformation> notAllowedCombination) {
Signature signature =
mappingInformation.isSignatureMappingInformation()
? mappingInformation.asSignatureMappingInformation().getSignature()
- : null;
+ : NO_SIGNATURE;
List<MappingInformation> additionalMappingForSignature =
additionalMappings.computeIfAbsent(signature, ignored -> new ArrayList<>());
- assert signature == null || additionalMappingForSignature.isEmpty();
+ for (MappingInformation information : additionalMappingForSignature) {
+ if (!information.allowOther(mappingInformation)) {
+ notAllowedCombination.accept(information);
+ }
+ }
additionalMappingForSignature.add(mappingInformation);
return this;
}
@@ -348,6 +379,10 @@
}
}
+ public Map<Signature, List<MappingInformation>> getAdditionalMappings() {
+ return additionalMappings;
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
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 bf0a8dd..51c3272 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -168,6 +168,40 @@
}
}
+ public static class NoSignature extends Signature {
+
+ public static final NoSignature NO_SIGNATURE = new NoSignature();
+
+ public 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/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index 2a67342..23a9a06 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
@@ -10,7 +11,6 @@
import com.android.tools.r8.naming.mappinginformation.SignatureMappingInformation;
import com.android.tools.r8.position.TextPosition;
import com.android.tools.r8.utils.IdentifierUtils;
-import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
@@ -62,20 +62,18 @@
private final BufferedReader reader;
private final JsonParser jsonParser = new JsonParser();
- private final Reporter reporter;
+ private final DiagnosticsHandler diagnosticsHandler;
@Override
public void close() throws IOException {
- if (reader != null) {
- reader.close();
- }
+ reader.close();
}
- ProguardMapReader(BufferedReader reader, Reporter reporter) {
+ ProguardMapReader(BufferedReader reader, DiagnosticsHandler diagnosticsHandler) {
this.reader = reader;
- this.reporter = reporter;
+ this.diagnosticsHandler = diagnosticsHandler;
assert reader != null;
- assert reporter != null;
+ assert diagnosticsHandler != null;
}
// Internal parser state
@@ -259,10 +257,14 @@
// Try to parse any information added in comments above member namings
if (isCommentLineWithJsonBrace()) {
MappingInformation mappingInfo =
- MappingInformation.fromJsonObject(parseJsonInComment(), reporter, lineNo);
- if (mappingInfo != null && mappingInfo.isSignatureMappingInformation()) {
- SignatureMappingInformation sigMapInfo = mappingInfo.asSignatureMappingInformation();
- mappingInformation.put(sigMapInfo.getSignature(), sigMapInfo);
+ MappingInformation.fromJsonObject(parseJsonInComment(), diagnosticsHandler, lineNo);
+ if (mappingInfo != null) {
+ if (mappingInfo.isSignatureMappingInformation()) {
+ SignatureMappingInformation sigMapInfo = mappingInfo.asSignatureMappingInformation();
+ mappingInformation.put(sigMapInfo.getSignature(), sigMapInfo);
+ } else {
+ classNamingBuilder.addMappingInformation(mappingInfo, diagnosticsHandler, lineNo);
+ }
}
// Skip reading the rest of the line.
lineOffset = line.length();
@@ -329,7 +331,7 @@
activeMemberNaming =
new MemberNaming(
signature,
- mappingInformation.get(signature).apply(signature, renamedName, reporter),
+ mappingInformation.get(signature).apply(signature, renamedName, diagnosticsHandler),
getPosition());
} else {
activeMemberNaming =
diff --git a/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java b/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
index 1e57331..e2bf357 100644
--- a/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
@@ -5,12 +5,12 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ProguardConfiguration;
import java.util.Arrays;
@@ -21,10 +21,12 @@
*/
public class SourceFileRewriter {
- private final AppView<AppInfoWithLiveness> appView;
+ private final AppView<?> appView;
+ private final DexApplication application;
- public SourceFileRewriter(AppView<AppInfoWithLiveness> appView) {
+ public SourceFileRewriter(AppView<?> appView, DexApplication application) {
this.appView = appView;
+ this.application = application;
}
public void run() {
@@ -37,16 +39,18 @@
&& appView.options().forceProguardCompatibility) {
return;
}
+ boolean isMinifying = appView.options().isMinifying();
+ assert !isMinifying || appView.appInfo().hasLiveness();
// Now, the user wants either to remove source file attribute or to rename it for non-kept
// classes.
DexString defaultRenaming = getSourceFileRenaming(proguardConfiguration);
- for (DexClass clazz : appView.appInfo().classes()) {
+ for (DexClass clazz : application.classes()) {
// We only parse sourceFile if -keepattributes SourceFile, but for compat we should add
// a source file name, otherwise line positions will not be printed on the JVM or old version
// of ART.
if (!hasRenameSourceFileAttribute
&& proguardConfiguration.getKeepAttributes().sourceFile
- && !appView.appInfo().isMinificationAllowed(clazz.type)) {
+ && !(isMinifying && appView.withLiveness().appInfo().isMinificationAllowed(clazz.type))) {
continue;
}
clazz.sourceFile = defaultRenaming;
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
new file mode 100644
index 0000000..87b3e7b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java
@@ -0,0 +1,70 @@
+// 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.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+
+public class FileNameInformation extends MappingInformation {
+
+ private final String fileName;
+
+ public static final String ID = "sourceFile";
+ static final String FILE_NAME_KEY = "fileName";
+
+ private FileNameInformation(String fileName) {
+ super(NO_LINE_NUMBER);
+ this.fileName = fileName;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ @Override
+ public String serialize() {
+ JsonObject result = new JsonObject();
+ result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
+ result.add(FILE_NAME_KEY, new JsonPrimitive(fileName));
+ return result.toString();
+ }
+
+ @Override
+ public boolean isFileNameInformation() {
+ return true;
+ }
+
+ @Override
+ public FileNameInformation asFileNameInformation() {
+ return this;
+ }
+
+ @Override
+ public boolean allowOther(MappingInformation information) {
+ return !information.isFileNameInformation();
+ }
+
+ public static FileNameInformation build(String fileName) {
+ return new FileNameInformation(fileName);
+ }
+
+ public static FileNameInformation build(
+ JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
+ try {
+ JsonElement fileName =
+ getJsonElementFromObject(object, diagnosticsHandler, lineNumber, FILE_NAME_KEY, ID);
+ if (fileName == null) {
+ return null;
+ }
+ return new FileNameInformation(fileName.getAsString());
+ } catch (UnsupportedOperationException | IllegalStateException ignored) {
+ diagnosticsHandler.info(
+ MappingInformationDiagnostics.invalidValueForObjectWithId(lineNumber, FILE_NAME_KEY, ID));
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/InformationParsingError.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/InformationParsingError.java
deleted file mode 100644
index 00e6dc5..0000000
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/InformationParsingError.java
+++ /dev/null
@@ -1,95 +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 com.android.tools.r8.Diagnostic;
-import com.android.tools.r8.Keep;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.position.Position;
-import com.android.tools.r8.position.TextPosition;
-
-@Keep
-public class InformationParsingError implements Diagnostic {
-
- private final String message;
- private final Position position;
-
- @Override
- public Origin getOrigin() {
- return Origin.unknown();
- }
-
- @Override
- public Position getPosition() {
- return position;
- }
-
- @Override
- public String getDiagnosticMessage() {
- return message;
- }
-
- private InformationParsingError(String message, Position position) {
- this.message = message;
- this.position = position;
- }
-
- static InformationParsingError noHandlerFor(int lineNumber, String value) {
- return new InformationParsingError(
- String.format("Could not find a handler for %s", value),
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError noKeyInJson(int lineNumber, String key) {
- return new InformationParsingError(
- String.format("Could not locate '%s' in the JSON object", key),
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError notValidJson(int lineNumber) {
- return new InformationParsingError(
- "Not valid JSON", new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError notValidString(int lineNumber, String key) {
- return new InformationParsingError(
- String.format("The value of '%s' is not a valid string in the JSON object", key),
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError tooManyInformationalParameters(int lineNumber) {
- return new InformationParsingError(
- "More informational parameters than actual parameters for method signature",
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError noKeyForObjectWithId(
- int lineNumber, String key, String mappingKey, String mappingValue) {
- return new InformationParsingError(
- String.format("Could not find '%s' for object with %s '%s'", key, mappingKey, mappingValue),
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError invalidValueForObjectWithId(
- int lineNumber, String mappingKey, String mappingValue) {
- return new InformationParsingError(
- String.format(
- "Could not decode the information for the object with %s '%s'",
- mappingKey, mappingValue),
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError tooManyEntriesForParameterInformation(int lineNumber) {
- return new InformationParsingError(
- "Parameter information do not have 1 or 2 entries",
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-
- static InformationParsingError invalidParameterInformationObject(int lineNumber) {
- return new InformationParsingError(
- "Parameter information is not an index and a string representation of a type",
- new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
- }
-}
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 f1f3296..c1c5105 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
@@ -4,7 +4,7 @@
package com.android.tools.r8.naming.mappinginformation;
-import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.DiagnosticsHandler;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -34,35 +34,63 @@
return null;
}
+ public boolean isFileNameInformation() {
+ return false;
+ }
+
+ public FileNameInformation asFileNameInformation() {
+ return null;
+ }
+
+ public boolean isMethodSignatureChangedInformation() {
+ return false;
+ }
+
+ public MethodSignatureChangedInformation asMethodSignatureChangedInformation() {
+ return null;
+ }
+
+ public abstract boolean allowOther(MappingInformation information);
+
public static MappingInformation fromJsonObject(
- JsonObject object, Reporter reporter, int lineNumber) {
+ JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
if (object == null) {
- reporter.info(InformationParsingError.notValidJson(lineNumber));
+ diagnosticsHandler.info(MappingInformationDiagnostics.notValidJson(lineNumber));
return null;
}
JsonElement id = object.get(MAPPING_ID_KEY);
if (id == null) {
- reporter.info(InformationParsingError.noKeyInJson(lineNumber, MAPPING_ID_KEY));
+ diagnosticsHandler.info(
+ MappingInformationDiagnostics.noKeyInJson(lineNumber, MAPPING_ID_KEY));
return null;
}
String idString = id.getAsString();
if (idString == null) {
- reporter.info(InformationParsingError.notValidString(lineNumber, MAPPING_ID_KEY));
+ diagnosticsHandler.info(
+ MappingInformationDiagnostics.notValidString(lineNumber, MAPPING_ID_KEY));
return null;
}
- if (idString.equals(MethodSignatureChangedInformation.ID)) {
- return MethodSignatureChangedInformation.build(object, reporter, lineNumber);
+ switch (idString) {
+ case MethodSignatureChangedInformation.ID:
+ return MethodSignatureChangedInformation.build(object, diagnosticsHandler, lineNumber);
+ case FileNameInformation.ID:
+ return FileNameInformation.build(object, diagnosticsHandler, lineNumber);
+ default:
+ diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, idString));
+ return null;
}
- reporter.info(InformationParsingError.noHandlerFor(lineNumber, idString));
- return null;
}
static JsonElement getJsonElementFromObject(
- JsonObject object, Reporter reporter, int lineNumber, String key, String id) {
+ JsonObject object,
+ DiagnosticsHandler diagnosticsHandler,
+ int lineNumber,
+ String key,
+ String id) {
JsonElement element = object.get(key);
if (element == null) {
- reporter.info(
- InformationParsingError.noKeyForObjectWithId(lineNumber, key, MAPPING_ID_KEY, id));
+ diagnosticsHandler.info(
+ MappingInformationDiagnostics.noKeyForObjectWithId(lineNumber, key, MAPPING_ID_KEY, id));
}
return element;
}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformationDiagnostics.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformationDiagnostics.java
new file mode 100644
index 0000000..6cc0b28
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformationDiagnostics.java
@@ -0,0 +1,113 @@
+// 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 com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+import com.android.tools.r8.position.TextPosition;
+
+@Keep
+public class MappingInformationDiagnostics implements Diagnostic {
+
+ private final String message;
+ private final Position position;
+
+ @Override
+ public Origin getOrigin() {
+ return Origin.unknown();
+ }
+
+ @Override
+ public Position getPosition() {
+ return position;
+ }
+
+ @Override
+ public String getDiagnosticMessage() {
+ return message;
+ }
+
+ private MappingInformationDiagnostics(String message, Position position) {
+ this.message = message;
+ this.position = position;
+ }
+
+ static MappingInformationDiagnostics noHandlerFor(int lineNumber, String value) {
+ return new MappingInformationDiagnostics(
+ String.format("Could not find a handler for %s", value),
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics noKeyInJson(int lineNumber, String key) {
+ return new MappingInformationDiagnostics(
+ String.format("Could not locate '%s' in the JSON object", key),
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics notValidJson(int lineNumber) {
+ return new MappingInformationDiagnostics(
+ "Not valid JSON", new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics notValidString(int lineNumber, String key) {
+ return new MappingInformationDiagnostics(
+ String.format("The value of '%s' is not a valid string in the JSON object", key),
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics tooManyInformationalParameters(int lineNumber) {
+ return new MappingInformationDiagnostics(
+ "More informational parameters than actual parameters for method signature",
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics noKeyForObjectWithId(
+ int lineNumber, String key, String mappingKey, String mappingValue) {
+ return new MappingInformationDiagnostics(
+ String.format("Could not find '%s' for object with %s '%s'", key, mappingKey, mappingValue),
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics invalidValueForObjectWithId(
+ int lineNumber, String mappingKey, String mappingValue) {
+ return new MappingInformationDiagnostics(
+ String.format(
+ "Could not decode the information for the object with %s '%s'",
+ mappingKey, mappingValue),
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics tooManyEntriesForParameterInformation(int lineNumber) {
+ return new MappingInformationDiagnostics(
+ "Parameter information do not have 1 or 2 entries",
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ static MappingInformationDiagnostics invalidParameterInformationObject(int lineNumber) {
+ return new MappingInformationDiagnostics(
+ "Parameter information is not an index and a string representation of a type",
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+
+ public static MappingInformationDiagnostics notAllowedCombination(
+ String className,
+ String renamedClassName,
+ MappingInformation one,
+ MappingInformation other,
+ int lineNumber) {
+ return new MappingInformationDiagnostics(
+ "The mapping '"
+ + one.serialize()
+ + "' is not allowed in combination with '"
+ + other.serialize()
+ + "' in the mapping for "
+ + className
+ + " -> "
+ + renamedClassName,
+ new TextPosition(1, lineNumber, TextPosition.UNKNOWN_COLUMN));
+ }
+}
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
index 32978ae..8bb023d 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java
@@ -4,9 +4,14 @@
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.android.tools.r8.utils.Reporter;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -58,12 +63,18 @@
}
@Override
+ public boolean allowOther(MappingInformation information) {
+ return !information.isMethodSignatureChangedInformation();
+ }
+
+ @Override
public Signature getSignature() {
return signature;
}
@Override
- public Signature apply(Signature originalSignature, String renamedName, Reporter reporter) {
+ 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;
@@ -74,7 +85,7 @@
int numberOfArgumentsRemoved = getNumberOfArgumentsRemoved();
if (numberOfArgumentsRemoved > parameters.length) {
// The mapping information is not up to date with the current signature.
- reporter.warning(InformationParsingError.tooManyInformationalParameters(getLineNumber()));
+ diagnosticsHandler.warning(tooManyInformationalParameters(getLineNumber()));
return new MethodSignature(renamedName, type, parameters);
}
String[] newParameters = new String[parameters.length - numberOfArgumentsRemoved];
@@ -86,7 +97,7 @@
} else {
if (insertIndex >= newParameters.length) {
// The mapping information is not up to date with the current signature.
- reporter.warning(InformationParsingError.tooManyInformationalParameters(getLineNumber()));
+ diagnosticsHandler.warning(tooManyInformationalParameters(getLineNumber()));
return new MethodSignature(renamedName, type, parameters);
} else if (argInfo == null) {
// Unchanged, take current parameter.
@@ -101,7 +112,7 @@
}
@Override
- public boolean hasChangedArguments() {
+ public boolean isMethodSignatureChangedInformation() {
return true;
}
@@ -134,7 +145,7 @@
}
@Override
- public MethodSignatureChangedInformation asArgumentsChangedInformation() {
+ public MethodSignatureChangedInformation asMethodSignatureChangedInformation() {
return this;
}
@@ -151,15 +162,16 @@
this.receiver = hasReceiver;
}
- public static MappingInformation build(JsonObject object, Reporter reporter, int lineNumber) {
+ public static MappingInformation build(
+ JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
try {
JsonElement returnTypeElement =
- getJsonElementFromObject(object, reporter, lineNumber, RETURN_TYPE_KEY, ID);
+ getJsonElementFromObject(object, diagnosticsHandler, lineNumber, RETURN_TYPE_KEY, ID);
JsonElement receiverElement =
- getJsonElementFromObject(object, reporter, lineNumber, RECEIVER_KEY, ID);
+ getJsonElementFromObject(object, diagnosticsHandler, lineNumber, RECEIVER_KEY, ID);
JsonElement argsElement =
- getJsonElementFromObject(object, reporter, lineNumber, PARAMS_KEY, ID);
- MethodSignature signature = getMethodSignature(object, ID, reporter, lineNumber);
+ getJsonElementFromObject(object, diagnosticsHandler, lineNumber, PARAMS_KEY, ID);
+ MethodSignature signature = getMethodSignature(object, ID, diagnosticsHandler, lineNumber);
if (signature == null
|| returnTypeElement == null
|| receiverElement == null
@@ -174,7 +186,7 @@
for (int i = 0; i < argumentsArray.size(); i++) {
args[i] =
ParameterInformation.fromJsonArray(
- argumentsArray.get(i).getAsJsonArray(), reporter, lineNumber);
+ argumentsArray.get(i).getAsJsonArray(), diagnosticsHandler, lineNumber);
}
return new MethodSignatureChangedInformation(
signature,
@@ -183,8 +195,7 @@
args,
lineNumber);
} catch (UnsupportedOperationException | IllegalStateException ignored) {
- reporter.info(
- InformationParsingError.invalidValueForObjectWithId(lineNumber, MAPPING_ID_KEY, ID));
+ diagnosticsHandler.info(invalidValueForObjectWithId(lineNumber, MAPPING_ID_KEY, ID));
return null;
}
}
@@ -207,11 +218,11 @@
}
static ParameterInformation fromJsonArray(
- JsonArray argumentInfo, Reporter reporter, int lineNumber) {
+ JsonArray argumentInfo, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
assert argumentInfo != null;
try {
if (argumentInfo.size() > 2) {
- reporter.info(InformationParsingError.tooManyEntriesForParameterInformation(lineNumber));
+ diagnosticsHandler.info(tooManyEntriesForParameterInformation(lineNumber));
return null;
}
int index = argumentInfo.get(0).getAsInt();
@@ -222,7 +233,7 @@
return new ParameterInformation(index, argumentInfo.get(1).getAsString());
}
} catch (UnsupportedOperationException | IllegalStateException ignored) {
- reporter.info(InformationParsingError.invalidParameterInformationObject(lineNumber));
+ diagnosticsHandler.info(invalidParameterInformationObject(lineNumber));
return null;
}
}
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
index 3659a6f..aba33bb 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java
@@ -4,9 +4,9 @@
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.android.tools.r8.utils.Reporter;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -31,16 +31,8 @@
public abstract Signature getSignature();
- public boolean hasChangedArguments() {
- return false;
- }
-
- public MethodSignatureChangedInformation asArgumentsChangedInformation() {
- return null;
- }
-
public abstract Signature apply(
- Signature originalSignature, String renamedName, Reporter reporter);
+ Signature originalSignature, String renamedName, DiagnosticsHandler diagnosticsHandler);
JsonObject serializeMethodSignature(JsonObject object, MethodSignature signature) {
JsonArray signatureArr = new JsonArray();
@@ -54,9 +46,9 @@
}
static MethodSignature getMethodSignature(
- JsonObject object, String id, Reporter reporter, int lineNumber) {
+ JsonObject object, String id, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
JsonElement signatureElement =
- getJsonElementFromObject(object, reporter, lineNumber, SIGNATURE_KEY, id);
+ getJsonElementFromObject(object, diagnosticsHandler, lineNumber, SIGNATURE_KEY, id);
if (signatureElement == null || !signatureElement.isJsonArray()) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index 3d59b8b..0cb273e 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -138,7 +138,8 @@
Timing timing = Timing.create("R8 retrace", command.printMemory());
timing.begin("Read proguard map");
ClassNameMapper classNameMapper =
- ClassNameMapper.mapperFromString(command.proguardMapProducer.get());
+ ClassNameMapper.mapperFromString(
+ command.proguardMapProducer.get(), command.diagnosticsHandler);
timing.end();
RetraceBase retraceBase = RetraceBaseImpl.create(classNameMapper);
RetraceCommandLineResult result;
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceBase.java b/src/main/java/com/android/tools/r8/retrace/RetraceBase.java
index 2874fc8..ee7d7ab 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceBase.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceBase.java
@@ -19,11 +19,5 @@
RetraceTypeResult retrace(TypeReference typeReference);
- String retraceSourceFile(ClassReference classReference, String sourceFile);
-
- String retraceSourceFile(
- ClassReference classReference,
- String sourceFile,
- ClassReference retracedClassReference,
- boolean hasRetraceResult);
+ RetraceSourceFileResult retraceSourceFile(ClassReference classReference, String sourceFile);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceBaseImpl.java b/src/main/java/com/android/tools/r8/retrace/RetraceBaseImpl.java
index 9a68706..1561457 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceBaseImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceBaseImpl.java
@@ -10,15 +10,9 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.utils.Box;
-import com.google.common.collect.Sets;
-import com.google.common.io.Files;
-import java.util.Set;
public class RetraceBaseImpl implements RetraceBase {
- private static final Set<String> UNKNOWN_SOURCEFILE_NAMES =
- Sets.newHashSet("", "SourceFile", "Unknown", "Unknown Source");
-
private final ClassNameMapper classNameMapper;
private RetraceBaseImpl(ClassNameMapper classNameMapper) {
@@ -46,10 +40,11 @@
}
@Override
- public String retraceSourceFile(ClassReference classReference, String sourceFile) {
- Box<String> retracedSourceFile = new Box<>();
+ public RetraceSourceFileResult retraceSourceFile(
+ ClassReference classReference, String sourceFile) {
+ Box<RetraceSourceFileResult> retracedSourceFile = new Box<>();
retrace(classReference)
- .forEach(element -> retracedSourceFile.set(element.retraceSourceFile(sourceFile, this)));
+ .forEach(element -> retracedSourceFile.set(element.retraceSourceFile(sourceFile)));
return retracedSourceFile.get();
}
@@ -57,42 +52,4 @@
public RetraceTypeResult retrace(TypeReference typeReference) {
return new RetraceTypeResult(typeReference, this);
}
-
- @Override
- public String retraceSourceFile(
- ClassReference obfuscatedClass,
- String sourceFile,
- ClassReference retracedClassReference,
- boolean hasRetraceResult) {
- boolean fileNameProbablyChanged =
- hasRetraceResult
- && !retracedClassReference.getTypeName().startsWith(obfuscatedClass.getTypeName());
- if (!UNKNOWN_SOURCEFILE_NAMES.contains(sourceFile) && !fileNameProbablyChanged) {
- // We have no new information, only rewrite filename if it is unknown.
- // PG-retrace will always rewrite the filename, but that seems a bit to harsh to do.
- return sourceFile;
- }
- if (!hasRetraceResult) {
- // We have no mapping but but the file name is unknown, so the best we can do is take the
- // name of the obfuscated clazz.
- assert obfuscatedClass.getTypeName().equals(retracedClassReference.getTypeName());
- return getClassSimpleName(obfuscatedClass.getTypeName()) + ".java";
- }
- String newFileName = getClassSimpleName(retracedClassReference.getTypeName());
- String extension = Files.getFileExtension(sourceFile);
- if (extension.isEmpty()) {
- extension = "java";
- }
- return newFileName + "." + extension;
- }
-
- private static String getClassSimpleName(String clazz) {
- int lastIndexOfPeriod = clazz.lastIndexOf('.');
- // Check if we can find a subclass separator.
- int endIndex = clazz.lastIndexOf('$');
- if (lastIndexOfPeriod > endIndex || endIndex < 0) {
- endIndex = clazz.length();
- }
- return clazz.substring(lastIndexOfPeriod + 1, endIndex);
- }
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
index 25505fe..a631ddf 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
@@ -4,10 +4,14 @@
package com.android.tools.r8.retrace;
+import static com.android.tools.r8.naming.MemberNaming.NoSignature.NO_SIGNATURE;
+import static com.android.tools.r8.retrace.RetraceUtils.synthesizeFileName;
+
import com.android.tools.r8.Keep;
import com.android.tools.r8.naming.ClassNamingForNameMapper;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
import com.android.tools.r8.naming.MemberNaming;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.retrace.RetraceClassResult.Element;
@@ -122,9 +126,26 @@
return classResult;
}
- public String retraceSourceFile(String fileName, RetraceBase retraceBase) {
- return retraceBase.retraceSourceFile(
- classResult.obfuscatedReference, fileName, classReference, mapper != null);
+ public RetraceSourceFileResult retraceSourceFile(String sourceFile) {
+ if (mapper != null && mapper.getAdditionalMappings().size() > 0) {
+ List<MappingInformation> mappingInformations =
+ mapper.getAdditionalMappings().get(NO_SIGNATURE);
+ if (mappingInformations != null) {
+ for (MappingInformation mappingInformation : mappingInformations) {
+ if (mappingInformation.isFileNameInformation()) {
+ return new RetraceSourceFileResult(
+ mappingInformation.asFileNameInformation().getFileName(), false);
+ }
+ }
+ }
+ }
+ return new RetraceSourceFileResult(
+ synthesizeFileName(
+ classReference.getTypeName(),
+ classResult.obfuscatedReference.getTypeName(),
+ sourceFile,
+ mapper != null),
+ true);
}
public RetraceFieldResult lookupField(String fieldName) {
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
index f0719ea..ff1af91 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
@@ -180,5 +180,9 @@
}
return mappedRange.getFirstLineNumberOfOriginalRange();
}
+
+ public RetraceSourceFileResult retraceSourceFile(String sourceFile) {
+ return RetraceUtils.getSourceFile(classElement, methodReference.getHolderClass(), sourceFile);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java b/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
index f1603f7..e2e78b2 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
@@ -671,20 +671,21 @@
retracedStrings.add(retraceString);
continue;
}
- String newSourceFile =
- retraceString.getQualifiedContext() != null
- ? retraceBase.retraceSourceFile(
- retraceString.classContext.getClassReference(),
- fileName,
+ RetraceSourceFileResult sourceFileResult =
+ retraceString.getMethodContext() != null
+ ? retraceString.getMethodContext().retraceSourceFile(fileName)
+ : RetraceUtils.getSourceFile(
+ retraceString.getClassContext(),
retraceString.getQualifiedContext(),
- true)
- : retraceString.classContext.retraceSourceFile(fileName, retraceBase);
+ fileName);
retracedStrings.add(
retraceString
.transform()
.setSource(fileName)
.replaceInString(
- newSourceFile, matcher.start(captureGroup), matcher.end(captureGroup))
+ sourceFileResult.getFilename(),
+ matcher.start(captureGroup),
+ matcher.end(captureGroup))
.build());
}
return retracedStrings;
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceSourceFileResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceSourceFileResult.java
new file mode 100644
index 0000000..4b21be1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceSourceFileResult.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.retrace;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public class RetraceSourceFileResult {
+
+ private final String filename;
+ private final boolean synthesized;
+
+ RetraceSourceFileResult(String filename, boolean synthesized) {
+ this.filename = filename;
+ this.synthesized = synthesized;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public boolean isSynthesized() {
+ return synthesized;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceStackTrace.java b/src/main/java/com/android/tools/r8/retrace/RetraceStackTrace.java
index c63a707..719dd44 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceStackTrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceStackTrace.java
@@ -421,7 +421,8 @@
List<StackTraceLine> lines,
String classLoaderName) {
ClassReference classReference = Reference.classFromTypeName(clazz);
- RetraceMethodResult retraceResult = retraceBase.retrace(classReference).lookupMethod(method);
+ RetraceClassResult classResult = retraceBase.retrace(classReference);
+ RetraceMethodResult retraceResult = classResult.lookupMethod(method);
if (linePosition != NO_POSITION && linePosition != INVALID_POSITION) {
retraceResult = retraceResult.narrowByLine(linePosition);
}
@@ -437,8 +438,7 @@
methodReference.getHolderClass().getTypeName(),
methodReference.getMethodName(),
methodDescriptionFromMethodReference(methodReference, verbose),
- retraceBase.retraceSourceFile(
- classReference, fileName, methodReference.getHolderClass(), true),
+ methodElement.retraceSourceFile(fileName).getFilename(),
hasLinePosition()
? methodElement.getOriginalLineNumber(linePosition)
: linePosition,
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java b/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
index 81c2272..c82bf36 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
@@ -4,11 +4,18 @@
package com.android.tools.r8.retrace;
+import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+import java.util.Set;
public class RetraceUtils {
+ private static final Set<String> UNKNOWN_SOURCEFILE_NAMES =
+ Sets.newHashSet("", "SourceFile", "Unknown", "Unknown Source");
+
public static String methodDescriptionFromMethodReference(
MethodReference methodReference, boolean verbose) {
if (!verbose || methodReference.isUnknown()) {
@@ -35,4 +42,64 @@
sb.append(")");
return sb.toString();
}
+
+ public static boolean hasPredictableSourceFileName(String originalClassName, String sourceFile) {
+ String synthesizedSourceFileName = getClassSimpleName(originalClassName) + ".java";
+ return synthesizedSourceFileName.equals(sourceFile);
+ }
+
+ private static String getClassSimpleName(String clazz) {
+ int lastIndexOfPeriod = clazz.lastIndexOf('.');
+ // Check if we can find a subclass separator.
+ int endIndex = clazz.lastIndexOf('$');
+ if (lastIndexOfPeriod > endIndex || endIndex < 0) {
+ endIndex = clazz.length();
+ }
+ return clazz.substring(lastIndexOfPeriod + 1, endIndex);
+ }
+
+ static RetraceSourceFileResult getSourceFile(
+ RetraceClassResult.Element classElement, ClassReference context, String sourceFile) {
+ // For inline frames we do not have the class element associated with it.
+ if (context == null) {
+ return classElement.retraceSourceFile(sourceFile);
+ }
+ if (context.equals(classElement.getClassReference())) {
+ return classElement.retraceSourceFile(sourceFile);
+ } else {
+ return new RetraceSourceFileResult(
+ synthesizeFileName(
+ context.getTypeName(),
+ classElement.getClassReference().getTypeName(),
+ sourceFile,
+ true),
+ true);
+ }
+ }
+
+ public static String synthesizeFileName(
+ String retracedClassName,
+ String minifiedClassName,
+ String sourceFile,
+ boolean hasRetraceResult) {
+ boolean fileNameProbablyChanged =
+ hasRetraceResult && !retracedClassName.startsWith(minifiedClassName);
+ if (!UNKNOWN_SOURCEFILE_NAMES.contains(sourceFile) && !fileNameProbablyChanged) {
+ // We have no new information, only rewrite filename if it is unknown.
+ // PG-retrace will always rewrite the filename, but that seems a bit to harsh to do.
+ return sourceFile;
+ }
+ String extension = Files.getFileExtension(sourceFile);
+ if (extension.isEmpty()) {
+ extension = "java";
+ }
+ if (!hasRetraceResult) {
+ // We have no mapping but but file name is unknown, so the best we can do is take the
+ // name of the obfuscated clazz.
+ assert minifiedClassName.equals(retracedClassName);
+ return getClassSimpleName(minifiedClassName) + "." + extension;
+ }
+ String newFileName = getClassSimpleName(retracedClassName);
+ return newFileName + "." + extension;
+ }
}
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 83f8ec0..552cc23 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -47,6 +47,8 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.Range;
+import com.android.tools.r8.naming.mappinginformation.FileNameInformation;
+import com.android.tools.r8.retrace.RetraceUtils;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.google.common.base.Suppliers;
@@ -287,6 +289,15 @@
originalType.toSourceString(),
com.android.tools.r8.position.Position.UNKNOWN));
+ // Check if source file should be added to the map
+ if (clazz.sourceFile != null) {
+ String sourceFile = clazz.sourceFile.toString();
+ if (!RetraceUtils.hasPredictableSourceFileName(clazz.toSourceString(), sourceFile)) {
+ Builder builder = onDemandClassNamingBuilder.get();
+ builder.addMappingInformation(FileNameInformation.build(sourceFile));
+ }
+ }
+
// If the class is renamed add it to the classNamingBuilder.
addClassToClassNaming(originalType, renamedClassName, onDemandClassNamingBuilder);
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 031b6c8..56fa95c 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
@@ -210,15 +211,15 @@
}
public T addKeepAttributeLineNumberTable() {
- return addKeepAttributes("LineNumberTable");
+ return addKeepAttributes(ProguardKeepAttributes.LINE_NUMBER_TABLE);
}
public T addKeepAttributeSourceFile() {
- return addKeepAttributes("SourceFile");
+ return addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE);
}
public T addKeepRuntimeVisibleAnnotations() {
- return addKeepAttributes("RuntimeVisibleAnnotations");
+ return addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS);
}
public T addKeepAllAttributes() {
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 2965085..8b68bd2 100644
--- a/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
@@ -16,7 +16,7 @@
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.mappinginformation.InformationParsingError;
+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;
@@ -67,7 +67,7 @@
allOf(
diagnosticMessage(containsString("Could not find a handler for bar")),
diagnosticPosition(positionLine(8)))))
- .assertAllInfosMatch(diagnosticType(InformationParsingError.class));
+ .assertAllInfosMatch(diagnosticType(MappingInformationDiagnostics.class));
}
@Test
@@ -111,7 +111,7 @@
allOf(
diagnosticMessage(containsString("Could not decode")),
diagnosticPosition(positionLine(8)))))
- .assertAllInfosMatch(diagnosticType(InformationParsingError.class));
+ .assertAllInfosMatch(diagnosticType(MappingInformationDiagnostics.class));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
index 2d5e31b..d2b2aba 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
@@ -280,6 +280,10 @@
}
public StackTrace retrace(String map) {
+ return retrace(map, null);
+ }
+
+ public StackTrace retrace(String map, String regularExpression) {
class Box {
List<String> result;
}
@@ -291,6 +295,7 @@
stackTraceLines.stream()
.map(line -> line.originalLine)
.collect(Collectors.toList()))
+ .setRegularExpression(regularExpression)
.setRetracedStackTraceConsumer(retraced -> box.result = retraced)
.build());
// Keep the original stderr in the retraced stacktrace.
diff --git a/src/test/java/com/android/tools/r8/retrace/DuplicateMappingsTest.java b/src/test/java/com/android/tools/r8/retrace/DuplicateMappingsTest.java
new file mode 100644
index 0000000..bbe2d5b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/DuplicateMappingsTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.retrace;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.DiagnosticsMatcher;
+import com.android.tools.r8.PositionMatcher;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessagesImpl;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class DuplicateMappingsTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public DuplicateMappingsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testSourceFileName() {
+ TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
+ Retrace.run(
+ RetraceCommand.builder(diagnosticsHandler)
+ .setProguardMapProducer(
+ () ->
+ StringUtils.lines(
+ "com.android.tools.r8.retrace.SourceFileTest$ClassWithCustomFileName ->"
+ + " com.android.tools.r8.retrace.a:",
+ "# {'id':'sourceFile','fileName':'foobarbaz.java'}",
+ "# {'id':'sourceFile','fileName':'foobarbaz2.java'}"))
+ .setStackTrace(ImmutableList.of())
+ .setRetracedStackTraceConsumer(
+ strings -> {
+ // No need to do anything, we are just checking for diagnostics.
+ })
+ .build());
+ diagnosticsHandler
+ .assertWarningsCount(1)
+ .assertWarningsMatch(
+ allOf(
+ DiagnosticsMatcher.diagnosticMessage(containsString("The mapping")),
+ DiagnosticsMatcher.diagnosticMessage(
+ containsString("is not allowed in combination with")),
+ DiagnosticsMatcher.diagnosticPosition(PositionMatcher.positionLine(3))));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/SourceFileTest.java b/src/test/java/com/android/tools/r8/retrace/SourceFileTest.java
new file mode 100644
index 0000000..fb7f280
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/SourceFileTest.java
@@ -0,0 +1,140 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.retrace;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.util.List;
+import java.util.function.BiConsumer;
+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 SourceFileTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final boolean useRegularExpression;
+ private static final String FILE_NAME = "foobarbaz.java";
+
+ @Parameters(name = "{0}, useRegularExpression: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+ }
+
+ public SourceFileTest(TestParameters parameters, boolean useRegularExpression) {
+ this.parameters = parameters;
+ this.useRegularExpression = useRegularExpression;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class, ClassWithoutCustomFileName.class)
+ .addProgramClassFileData(
+ transformer(ClassWithCustomFileName.class).setSourceFile(FILE_NAME).transform())
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+ .inspectStackTrace(
+ stackTrace -> {
+ assertEquals(FILE_NAME, stackTrace.getStackTraceLines().get(0).fileName);
+ });
+ }
+
+ @Test
+ public void testR8WithCustomFileName() throws Exception {
+ runTest(
+ false,
+ ((stackTrace, inspector) -> {
+ assertEquals(FILE_NAME, stackTrace.getStackTraceLines().get(0).fileName);
+ assertEquals(
+ 1,
+ inspector
+ .clazz(ClassWithCustomFileName.class)
+ .getNaming()
+ .getAdditionalMappings()
+ .size());
+ }));
+ }
+
+ @Test
+ public void testR8WithoutCustomFileName() throws Exception {
+ runTest(
+ true,
+ ((stackTrace, inspector) -> {
+ assertEquals("SourceFileTest.java", stackTrace.getStackTraceLines().get(0).fileName);
+ assertEquals(
+ 0,
+ inspector
+ .clazz(ClassWithoutCustomFileName.class)
+ .getNaming()
+ .getAdditionalMappings()
+ .size());
+ }));
+ }
+
+ private void runTest(boolean addDummyArg, BiConsumer<StackTrace, CodeInspector> consumer)
+ throws Exception {
+ R8FullTestBuilder r8FullTestBuilder =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class, ClassWithoutCustomFileName.class)
+ .addProgramClassFileData(
+ transformer(ClassWithCustomFileName.class).setSourceFile(FILE_NAME).transform())
+ .addKeepClassRules(ClassWithoutCustomFileName.class)
+ .enableInliningAnnotations()
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepAttributeSourceFile();
+ R8TestRunResult runResult =
+ addDummyArg
+ ? r8FullTestBuilder.run(parameters.getRuntime(), Main.class, "foo")
+ : r8FullTestBuilder.run(parameters.getRuntime(), Main.class);
+ runResult.assertFailureWithErrorThatMatches(containsString("Hello World!"));
+ StackTrace originalStackTrace = runResult.getOriginalStackTrace();
+ StackTrace retracedStackTrace =
+ originalStackTrace.retrace(
+ runResult.proguardMap(),
+ useRegularExpression ? Retrace.DEFAULT_REGULAR_EXPRESSION : null);
+ runResult.inspectFailure(inspector -> consumer.accept(retracedStackTrace, inspector));
+ }
+
+ public static class ClassWithoutCustomFileName {
+
+ @NeverInline
+ public static void foo() {
+ throw new RuntimeException("Hello World!");
+ }
+ }
+
+ public static class ClassWithCustomFileName {
+
+ @NeverInline
+ public static void foo() {
+ throw new RuntimeException("Hello World!");
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ ClassWithCustomFileName.foo();
+ } else {
+ ClassWithoutCustomFileName.foo();
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index 1f1d744..c34dc98 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -266,6 +266,16 @@
});
}
+ public ClassFileTransformer setSourceFile(String sourceFile) {
+ return addClassTransformer(
+ new ClassTransformer() {
+ @Override
+ public void visitSource(String source, String debug) {
+ super.visitSource(sourceFile, debug);
+ }
+ });
+ }
+
public ClassFileTransformer setAccessFlags(Consumer<ClassAccessFlags> fn) {
return addClassTransformer(
new ClassTransformer() {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index 6a04a0a..59c8760 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.naming.ClassNamingForNameMapper;
import com.android.tools.r8.references.ClassReference;
import java.util.List;
import java.util.function.Consumer;
@@ -177,4 +178,9 @@
public KotlinClassMetadata getKotlinClassMetadata() {
return null;
}
+
+ @Override
+ public ClassNamingForNameMapper getNaming() {
+ return null;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 84d76a1..b2266ce 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.naming.ClassNamingForNameMapper;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
@@ -211,4 +212,6 @@
Reference.classFromDescriptor(
descriptor.substring(0, descriptor.length() - 1) + COMPANION_CLASS_NAME_SUFFIX + ";"));
}
+
+ public abstract ClassNamingForNameMapper getNaming();
}
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 bd65812..0b1d950 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
@@ -403,4 +403,9 @@
return KotlinClassMetadataReader.toKotlinClassMetadata(
codeInspector.getFactory().kotlin, annotationSubject.getAnnotation());
}
+
+ @Override
+ public ClassNamingForNameMapper getNaming() {
+ return naming;
+ }
}