Add GenericSignatureTypeRewriter and use it for rewriting
The CL adds GenericSignatureTypeRewriter and adds the new
GenericSignature for parsing and type-rewriting.
Bug: 170915828
Bug: 154793333
Change-Id: I7c4ba9e8bf5752abf2a19e261804b7895de11f34
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 2b75c58..24a99a0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -341,7 +341,7 @@
appView.options().reporter);
}
}
- return ClassSignature.NO_CLASS_SIGNATURE;
+ return ClassSignature.noSignature();
}
private boolean verifyCorrectnessOfFieldHolder(DexEncodedField field) {
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignature.java b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
index 9c34474..a92dc75 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -174,7 +174,7 @@
public static class ClassSignature implements DexDefinitionSignature<DexClass> {
- public static final ClassSignature NO_CLASS_SIGNATURE =
+ private static final ClassSignature NO_CLASS_SIGNATURE =
new ClassSignature(EMPTY_TYPE_PARAMS, NO_FIELD_TYPE_SIGNATURE, EMPTY_SUPER_INTERFACES);
final List<FormalTypeParameter> formalTypeParameters;
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
new file mode 100644
index 0000000..c95ce02
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
@@ -0,0 +1,326 @@
+// 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.graph;
+
+import static com.android.tools.r8.graph.GenericSignature.EMPTY_SUPER_INTERFACES;
+import static com.android.tools.r8.graph.GenericSignature.EMPTY_TYPE_ARGUMENTS;
+import static com.android.tools.r8.graph.GenericSignature.EMPTY_TYPE_PARAMS;
+import static com.android.tools.r8.graph.GenericSignature.EMPTY_TYPE_SIGNATURES;
+import static com.android.tools.r8.graph.GenericSignature.FieldTypeSignature.noSignature;
+import static com.android.tools.r8.graph.GenericSignature.StarFieldTypeSignature.STAR_FIELD_TYPE_SIGNATURE;
+
+import com.android.tools.r8.graph.GenericSignature.ArrayTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature;
+import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter;
+import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.ReturnType;
+import com.android.tools.r8.graph.GenericSignature.TypeSignature;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenericSignatureTypeRewriter {
+
+ private final AppView<?> appView;
+ private final DexProgramClass context;
+
+ private final FieldTypeSignature objectTypeSignature;
+
+ public GenericSignatureTypeRewriter(AppView<?> appView, DexProgramClass context) {
+ this.appView = appView;
+ this.context = context;
+ objectTypeSignature =
+ new ClassTypeSignature(appView.dexItemFactory().objectType, EMPTY_TYPE_ARGUMENTS);
+ }
+
+ public ClassSignature rewrite(ClassSignature classSignature) {
+ if (classSignature.hasNoSignature()) {
+ return classSignature;
+ }
+ return new ClassSignatureRewriter().run(classSignature);
+ }
+
+ public FieldTypeSignature rewrite(FieldTypeSignature fieldTypeSignature) {
+ if (fieldTypeSignature.hasNoSignature()) {
+ return fieldTypeSignature;
+ }
+ return new TypeSignatureRewriter().run(fieldTypeSignature);
+ }
+
+ public MethodTypeSignature rewrite(MethodTypeSignature methodTypeSignature) {
+ if (methodTypeSignature.hasNoSignature()) {
+ return methodTypeSignature;
+ }
+ return new MethodTypeSignatureRewriter().run(methodTypeSignature);
+ }
+
+ private class ClassSignatureRewriter implements GenericSignatureVisitor {
+
+ private final List<FormalTypeParameter> rewrittenTypeParameters = new ArrayList<>();
+ private ClassTypeSignature rewrittenSuperClass;
+ private final List<ClassTypeSignature> rewrittenSuperInterfaces = new ArrayList<>();
+
+ @Override
+ public void visitClassSignature(ClassSignature classSignature) {
+ classSignature.visit(this);
+ }
+
+ @Override
+ public void visitFormalTypeParameters(List<FormalTypeParameter> formalTypeParameters) {
+ for (FormalTypeParameter formalTypeParameter : formalTypeParameters) {
+ rewrittenTypeParameters.add(new FormalTypeParameterRewriter().run(formalTypeParameter));
+ }
+ }
+
+ @Override
+ public void visitSuperClass(ClassTypeSignature classTypeSignature) {
+ rewrittenSuperClass = new ClassTypeSignatureRewriter(true).run(classTypeSignature);
+ if (rewrittenSuperClass == null) {
+ rewrittenSuperClass =
+ new ClassTypeSignature(appView.dexItemFactory().objectType, EMPTY_TYPE_ARGUMENTS);
+ }
+ }
+
+ @Override
+ public void visitSuperInterface(ClassTypeSignature classTypeSignature) {
+ ClassTypeSignature superInterface =
+ new ClassTypeSignatureRewriter(true).run(classTypeSignature);
+ if (superInterface != null) {
+ rewrittenSuperInterfaces.add(superInterface);
+ }
+ }
+
+ private ClassSignature run(ClassSignature classSignature) {
+ classSignature.visit(this);
+ if (rewrittenTypeParameters.isEmpty()
+ && rewrittenSuperInterfaces.isEmpty()
+ && rewrittenSuperClass.isNoSignature()
+ && rewrittenSuperClass.type == appView.dexItemFactory().objectType) {
+ return ClassSignature.noSignature();
+ }
+ return new ClassSignature(
+ rewrittenTypeParameters.isEmpty() ? EMPTY_TYPE_PARAMS : rewrittenTypeParameters,
+ rewrittenSuperClass,
+ rewrittenSuperInterfaces.isEmpty() ? EMPTY_SUPER_INTERFACES : rewrittenSuperInterfaces);
+ }
+ }
+
+ private class MethodTypeSignatureRewriter implements GenericSignatureVisitor {
+
+ private final List<FormalTypeParameter> rewrittenTypeParameters = new ArrayList<>();
+ private final List<TypeSignature> rewrittenTypeSignatures = new ArrayList<>();
+
+ ReturnType rewrittenReturnType = null;
+ private final List<TypeSignature> rewrittenThrowsSignatures = new ArrayList<>();
+
+ @Override
+ public void visitFormalTypeParameters(List<FormalTypeParameter> formalTypeParameters) {
+ for (FormalTypeParameter formalTypeParameter : formalTypeParameters) {
+ rewrittenTypeParameters.add(new FormalTypeParameterRewriter().run(formalTypeParameter));
+ }
+ }
+
+ @Override
+ public void visitMethodTypeSignatures(List<TypeSignature> typeSignatures) {
+ for (TypeSignature typeSignature : typeSignatures) {
+ TypeSignature rewrittenType = new TypeSignatureRewriter().run(typeSignature);
+ rewrittenTypeSignatures.add(rewrittenType == null ? objectTypeSignature : rewrittenType);
+ }
+ }
+
+ @Override
+ public void visitReturnType(ReturnType returnType) {
+ if (returnType.isVoidDescriptor()) {
+ rewrittenReturnType = ReturnType.VOID;
+ } else {
+ TypeSignature originalType = returnType.typeSignature();
+ TypeSignature rewrittenType = new TypeSignatureRewriter().run(originalType);
+ if (rewrittenType == null) {
+ rewrittenReturnType = ReturnType.VOID;
+ } else if (rewrittenType == originalType) {
+ rewrittenReturnType = returnType;
+ } else {
+ rewrittenReturnType = new ReturnType(rewrittenType);
+ }
+ }
+ }
+
+ @Override
+ public void visitThrowsSignatures(List<TypeSignature> typeSignatures) {
+ for (TypeSignature typeSignature : typeSignatures) {
+ TypeSignature rewrittenType = new TypeSignatureRewriter().run(typeSignature);
+ // If a throwing type is no longer found we remove it from the signature.
+ if (rewrittenType != null) {
+ rewrittenThrowsSignatures.add(rewrittenType);
+ }
+ }
+ }
+
+ private MethodTypeSignature run(MethodTypeSignature methodTypeSignature) {
+ methodTypeSignature.visit(this);
+ assert rewrittenReturnType != null;
+ if (rewrittenTypeParameters.isEmpty()
+ && rewrittenTypeSignatures.isEmpty()
+ && rewrittenReturnType.isVoidDescriptor()
+ && rewrittenThrowsSignatures.isEmpty()) {
+ return MethodTypeSignature.noSignature();
+ }
+ return new MethodTypeSignature(
+ rewrittenTypeParameters.isEmpty() ? EMPTY_TYPE_PARAMS : rewrittenTypeParameters,
+ rewrittenTypeSignatures.isEmpty() ? EMPTY_TYPE_SIGNATURES : rewrittenTypeSignatures,
+ rewrittenReturnType,
+ rewrittenThrowsSignatures.isEmpty() ? EMPTY_TYPE_SIGNATURES : rewrittenThrowsSignatures);
+ }
+ }
+
+ private class FormalTypeParameterRewriter implements GenericSignatureVisitor {
+
+ private FieldTypeSignature rewrittenClassBound = noSignature();
+ private final List<FieldTypeSignature> rewrittenInterfaceBounds = new ArrayList<>();
+
+ @Override
+ public void visitClassBound(FieldTypeSignature fieldSignature) {
+ rewrittenClassBound = new TypeSignatureRewriter().run(fieldSignature);
+ }
+
+ @Override
+ public void visitInterfaceBound(FieldTypeSignature fieldSignature) {
+ FieldTypeSignature interfaceBound = new TypeSignatureRewriter().run(fieldSignature);
+ if (interfaceBound != null) {
+ rewrittenInterfaceBounds.add(interfaceBound);
+ }
+ }
+
+ private FormalTypeParameter run(FormalTypeParameter formalTypeParameter) {
+ formalTypeParameter.visit(this);
+ // Guard against the case where we have <T::...> that is, no class or interfaces bounds.
+ if (rewrittenInterfaceBounds.isEmpty()
+ && (rewrittenClassBound == null || !rewrittenClassBound.hasSignature())) {
+ rewrittenClassBound = objectTypeSignature;
+ }
+ return new FormalTypeParameter(
+ formalTypeParameter.name,
+ rewrittenClassBound == null ? noSignature() : rewrittenClassBound,
+ rewrittenInterfaceBounds.isEmpty() ? EMPTY_TYPE_ARGUMENTS : rewrittenInterfaceBounds);
+ }
+ }
+
+ private class TypeSignatureRewriter implements GenericSignatureVisitor {
+
+ private TypeSignature run(TypeSignature typeSignature) {
+ if (typeSignature.isBaseTypeSignature()) {
+ return typeSignature;
+ }
+ assert typeSignature.isFieldTypeSignature();
+ return run(typeSignature.asFieldTypeSignature());
+ }
+
+ private FieldTypeSignature run(FieldTypeSignature fieldTypeSignature) {
+ if (fieldTypeSignature.isStar()) {
+ return fieldTypeSignature;
+ }
+ if (fieldTypeSignature.isTypeVariableSignature()) {
+ return fieldTypeSignature;
+ }
+ if (fieldTypeSignature.isArrayTypeSignature()) {
+ ArrayTypeSignature arrayTypeSignature = fieldTypeSignature.asArrayTypeSignature();
+ TypeSignature rewrittenElement = run(arrayTypeSignature.elementSignature);
+ if (rewrittenElement == null) {
+ return new ArrayTypeSignature(objectTypeSignature);
+ }
+ return rewrittenElement.toArrayTypeSignature();
+ }
+ assert fieldTypeSignature.isClassTypeSignature();
+ ClassTypeSignature classTypeSignature = fieldTypeSignature.asClassTypeSignature();
+ if (classTypeSignature.isNoSignature()) {
+ return classTypeSignature;
+ }
+ return new ClassTypeSignatureRewriter(false).run(classTypeSignature);
+ }
+ }
+
+ private class ClassTypeSignatureRewriter implements GenericSignatureVisitor {
+
+ private final AppInfoWithLiveness appInfoWithLiveness;
+ private final boolean isSuperClassOrInterface;
+
+ // These fields are updated when iterating the modeled structure.
+ private DexType currentType;
+
+ // The following references are used to have a head and tail pointer to the classTypeSignature
+ // link we are building. The topClassSignature will have a reference to the top-most package
+ // and class-name. The parentClassSignature is a pointer pointing to the tail always and will
+ // be linked and updated when calling ClassTypeSignature.link.
+ private ClassTypeSignature topClassSignature;
+ private ClassTypeSignature parentClassSignature;
+
+ private ClassTypeSignatureRewriter(boolean isSuperClassOrInterface) {
+ appInfoWithLiveness =
+ appView.appInfo().hasLiveness() ? appView.appInfo().withLiveness() : null;
+ this.isSuperClassOrInterface = isSuperClassOrInterface;
+ }
+
+ @Override
+ public void visitSimpleClass(ClassTypeSignature classTypeSignature) {
+ currentType = getTarget(classTypeSignature.type);
+ if (currentType == null) {
+ return;
+ }
+ classTypeSignature.visit(this);
+ }
+
+ @Override
+ public void visitTypeArguments(List<FieldTypeSignature> typeArguments) {
+ ClassTypeSignature newClassTypeSignature;
+ if (typeArguments.isEmpty()) {
+ newClassTypeSignature = new ClassTypeSignature(currentType, EMPTY_TYPE_ARGUMENTS);
+ } else {
+ List<FieldTypeSignature> rewrittenTypeArguments = new ArrayList<>(typeArguments.size());
+ for (FieldTypeSignature typeArgument : typeArguments) {
+ if (typeArgument.isStar()) {
+ rewrittenTypeArguments.add(typeArgument);
+ continue;
+ }
+ FieldTypeSignature rewritten = new TypeSignatureRewriter().run(typeArgument);
+ if (rewritten != null) {
+ rewrittenTypeArguments.add(rewritten.asArgument(typeArgument.getWildcardIndicator()));
+ } else {
+ rewrittenTypeArguments.add(STAR_FIELD_TYPE_SIGNATURE);
+ }
+ }
+ newClassTypeSignature = new ClassTypeSignature(currentType, rewrittenTypeArguments);
+ }
+ if (topClassSignature == null) {
+ topClassSignature = newClassTypeSignature;
+ parentClassSignature = newClassTypeSignature;
+ } else {
+ ClassTypeSignature.link(parentClassSignature, newClassTypeSignature);
+ parentClassSignature = newClassTypeSignature;
+ }
+ }
+
+ private ClassTypeSignature run(ClassTypeSignature classTypeSignature) {
+ currentType = getTarget(classTypeSignature.type);
+ if (currentType == null) {
+ return null;
+ }
+ classTypeSignature.visit(this);
+ return topClassSignature;
+ }
+
+ private DexType getTarget(DexType type) {
+ DexType rewrittenType = appView.graphLense().lookupType(type);
+ if (appInfoWithLiveness != null && appInfoWithLiveness.wasPruned(rewrittenType)) {
+ return null;
+ }
+ if (isSuperClassOrInterface && context.type == rewrittenType) {
+ return null;
+ }
+ return rewrittenType;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index 1f66108..fd5dc11 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -4,28 +4,25 @@
package com.android.tools.r8.naming.signature;
-import static com.android.tools.r8.utils.DescriptorUtils.getClassBinaryNameFromDescriptor;
-import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromClassBinaryName;
-
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GenericSignature;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature;
+import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import com.android.tools.r8.graph.GenericSignatureTypeRewriter;
import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.PredicateUtils;
import com.android.tools.r8.utils.Reporter;
-import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
-import java.lang.reflect.GenericSignatureFormatError;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
-import java.util.function.Supplier;
// TODO(b/129925954): Reimplement this by using the internal encoding and transformation logic.
public class GenericSignatureRewriter {
@@ -34,12 +31,14 @@
private final NamingLens namingLens;
private final InternalOptions options;
private final Reporter reporter;
+ private final Predicate<DexType> isTypeMissing;
public GenericSignatureRewriter(AppView<?> appView, NamingLens namingLens) {
this.appView = appView;
this.namingLens = namingLens;
this.options = appView.options();
this.reporter = options.reporter;
+ isTypeMissing = PredicateUtils.isNull(appView.appInfo()::definitionForWithoutExistenceAssert);
}
public void run(Iterable<? extends DexProgramClass> classes, ExecutorService executorService)
@@ -56,51 +55,77 @@
ThreadUtils.processItems(
classes,
clazz -> {
- GenericSignatureCollector genericSignatureCollector =
- new GenericSignatureCollector(clazz);
- GenericSignatureParser<DexType> genericSignatureParser =
- new GenericSignatureParser<>(genericSignatureCollector);
+ GenericSignatureTypeRewriter typeRewriter =
+ new GenericSignatureTypeRewriter(appView, clazz);
clazz.setAnnotations(
rewriteGenericSignatures(
clazz.annotations(),
- genericSignatureParser::parseClassSignature,
- genericSignatureCollector::getRenamedSignature,
- (signature, e) ->
- options.warningInvalidSignature(clazz, clazz.getOrigin(), signature, e)));
+ signature -> {
+ ClassSignature classSignature =
+ GenericSignature.parseClassSignature(
+ clazz.toSourceString(),
+ signature,
+ clazz.origin,
+ appView.dexItemFactory(),
+ options.reporter);
+ if (classSignature.hasNoSignature()) {
+ return null;
+ }
+ return typeRewriter
+ .rewrite(classSignature)
+ .toRenamedString(namingLens, isTypeMissing);
+ }));
clazz.forEachField(
field ->
field.setAnnotations(
rewriteGenericSignatures(
field.annotations(),
- genericSignatureParser::parseFieldSignature,
- genericSignatureCollector::getRenamedSignature,
- (signature, e) ->
- options.warningInvalidSignature(
- field, clazz.getOrigin(), signature, e))));
+ signature -> {
+ FieldTypeSignature fieldSignature =
+ GenericSignature.parseFieldTypeSignature(
+ field.toSourceString(),
+ signature,
+ clazz.origin,
+ appView.dexItemFactory(),
+ options.reporter);
+ if (fieldSignature.hasNoSignature()) {
+ return null;
+ }
+ return typeRewriter
+ .rewrite(fieldSignature)
+ .toRenamedString(namingLens, isTypeMissing);
+ })));
clazz.forEachMethod(
method ->
method.setAnnotations(
rewriteGenericSignatures(
method.annotations(),
- genericSignatureParser::parseMethodSignature,
- genericSignatureCollector::getRenamedSignature,
- (signature, e) ->
- options.warningInvalidSignature(
- method, clazz.getOrigin(), signature, e))));
+ signature -> {
+ MethodTypeSignature methodSignature =
+ GenericSignature.parseMethodSignature(
+ method.toSourceString(),
+ signature,
+ clazz.origin,
+ appView.dexItemFactory(),
+ options.reporter);
+ if (methodSignature.hasNoSignature()) {
+ return null;
+ }
+ return typeRewriter
+ .rewrite(methodSignature)
+ .toRenamedString(namingLens, isTypeMissing);
+ })));
},
executorService);
}
private DexAnnotationSet rewriteGenericSignatures(
- DexAnnotationSet annotations,
- Consumer<String> parser,
- Supplier<String> collector,
- BiConsumer<String, GenericSignatureFormatError> parseError) {
+ DexAnnotationSet annotations, Function<String, String> rewrite) {
// There can be no more than one signature annotation in an annotation set.
final int VALID = -1;
- int invalid = VALID;
+ int invalidOrPrunedIndex = VALID;
DexAnnotation[] rewrittenAnnotations = null;
- for (int i = 0; i < annotations.annotations.length && invalid == VALID; i++) {
+ for (int i = 0; i < annotations.annotations.length && invalidOrPrunedIndex == VALID; i++) {
DexAnnotation annotation = annotations.annotations[i];
if (DexAnnotation.isSignatureAnnotation(annotation, appView.dexItemFactory())) {
if (rewrittenAnnotations == null) {
@@ -108,16 +133,12 @@
System.arraycopy(annotations.annotations, 0, rewrittenAnnotations, 0, i);
}
String signature = DexAnnotation.getSignature(annotation);
- try {
- parser.accept(signature);
- String renamedSignature = collector.get();
- assert verifyConsistentRenaming(parser, collector, renamedSignature);
- DexAnnotation signatureAnnotation =
- DexAnnotation.createSignatureAnnotation(renamedSignature, appView.dexItemFactory());
- rewrittenAnnotations[i] = signatureAnnotation;
- } catch (GenericSignatureFormatError e) {
- parseError.accept(signature, e);
- invalid = i;
+ String rewrittenSignature = rewrite.apply(signature);
+ if (rewrittenSignature != null) {
+ rewrittenAnnotations[i] =
+ DexAnnotation.createSignatureAnnotation(rewrittenSignature, appView.dexItemFactory());
+ } else {
+ invalidOrPrunedIndex = i;
}
} else if (rewrittenAnnotations != null) {
rewrittenAnnotations[i] = annotation;
@@ -125,7 +146,7 @@
}
// Return the rewritten signatures if it was valid and could be rewritten.
- if (invalid == VALID) {
+ if (invalidOrPrunedIndex == VALID) {
return rewrittenAnnotations != null
? new DexAnnotationSet(rewrittenAnnotations)
: annotations;
@@ -135,156 +156,11 @@
new DexAnnotation[annotations.annotations.length - 1];
int dest = 0;
for (int i = 0; i < annotations.annotations.length; i++) {
- if (i != invalid) {
+ if (i != invalidOrPrunedIndex) {
prunedAnnotations[dest++] = annotations.annotations[i];
}
}
assert dest == prunedAnnotations.length;
return new DexAnnotationSet(prunedAnnotations);
}
-
- /**
- * Calling this method will clobber the parsed signature in the collector - ideally with the same
- * string. Only use this after the original result has been collected.
- */
- private boolean verifyConsistentRenaming(
- Consumer<String> parser, Supplier<String> collector, String renamedSignature) {
- if (!options.testing.assertConsistentRenamingOfSignature) {
- return true;
- }
- parser.accept(renamedSignature);
- String reRenamedSignature = collector.get();
- assert renamedSignature.equals(reRenamedSignature);
- return true;
- }
-
- private class GenericSignatureCollector implements GenericSignatureAction<DexType> {
- private StringBuilder renamedSignature;
- private final DexProgramClass currentClassContext;
- private DexType lastWrittenType = null;
-
- GenericSignatureCollector(DexProgramClass clazz) {
- this.currentClassContext = clazz;
- }
-
- String getRenamedSignature() {
- return renamedSignature.toString();
- }
-
- @Override
- public void parsedSymbol(char symbol) {
- if (symbol == ';' && lastWrittenType == null) {
- // The type was never written (maybe because it was merged with it's subtype).
- return;
- }
- // If the super-class or interface has been merged, we will stop writing out type
- // arguments, resulting in a signature on the form '<>' if we do not remove it.
- if (symbol == '>' && removeWrittenCharacter(c -> c == '<')) {
- return;
- }
- renamedSignature.append(symbol);
- }
-
- @Override
- public void parsedIdentifier(String identifier) {
- renamedSignature.append(identifier);
- }
-
- @Override
- public DexType parsedTypeName(String name, ParserPosition parserPosition) {
- if (parserPosition == ParserPosition.ENCLOSING_INNER_OR_TYPE_ANNOTATION
- && lastWrittenType == null) {
- // We are writing type-arguments for a merged class.
- removeWrittenClassCharacter();
- return null;
- }
- String originalDescriptor = getDescriptorFromClassBinaryName(name);
- DexType type =
- appView.graphLense().lookupType(appView.dexItemFactory().createType(originalDescriptor));
- if (appView.appInfo().hasLiveness() && appView.withLiveness().appInfo().wasPruned(type)) {
- type = appView.dexItemFactory().objectType;
- }
- DexString renamedDescriptor = namingLens.lookupDescriptor(type);
- if (parserPosition == ParserPosition.CLASS_SUPER_OR_INTERFACE_ANNOTATION
- && currentClassContext != null) {
- // We may have merged the type down to the current class type.
- DexString classDescriptor = currentClassContext.type.descriptor;
- if (!originalDescriptor.equals(classDescriptor.toString())
- && renamedDescriptor.equals(classDescriptor)) {
- lastWrittenType = null;
- removeWrittenClassCharacter();
- return type;
- }
- }
- renamedSignature.append(getClassBinaryNameFromDescriptor(renamedDescriptor.toString()));
- lastWrittenType = type;
- return type;
- }
-
- private boolean removeWrittenCharacter(Predicate<Character> removeIf) {
- int index = renamedSignature.length() - 1;
- if (index < 0 || !removeIf.test(renamedSignature.charAt(index))) {
- return false;
- }
- renamedSignature.deleteCharAt(index);
- return true;
- }
-
- private void removeWrittenClassCharacter() {
- removeWrittenCharacter(c -> c == 'L');
- }
-
- @Override
- public DexType parsedInnerTypeName(DexType enclosingType, String name) {
- if (enclosingType == null) {
- // We are writing inner type names
- removeWrittenClassCharacter();
- return null;
- }
- assert enclosingType.isClassType();
- String enclosingDescriptor = enclosingType.toDescriptorString();
- DexType type =
- appView
- .dexItemFactory()
- .createType(
- getDescriptorFromClassBinaryName(
- getClassBinaryNameFromDescriptor(enclosingDescriptor)
- + DescriptorUtils.INNER_CLASS_SEPARATOR
- + name));
- type = appView.graphLense().lookupType(type);
- String renamedDescriptor = namingLens.lookupDescriptor(type).toString();
- if (!renamedDescriptor.equals(type.toDescriptorString())) {
- // TODO(b/147504070): If this is a merged class equal to the class context, do not add.
- // Pick the renamed inner class from the fully renamed binary name.
- String fullRenamedBinaryName = getClassBinaryNameFromDescriptor(renamedDescriptor);
- String enclosingRenamedBinaryName =
- getClassBinaryNameFromDescriptor(namingLens.lookupDescriptor(enclosingType).toString());
- int innerClassPos = enclosingRenamedBinaryName.length() + 1;
- if (innerClassPos < fullRenamedBinaryName.length()) {
- renamedSignature.append(fullRenamedBinaryName.substring(innerClassPos));
- } else if (appView.options().keepInnerClassStructure()) {
- reporter.warning(
- new StringDiagnostic(
- "Should have retained InnerClasses attribute of " + type + ".",
- appView.appInfo().originFor(type)));
- renamedSignature.append(name);
- }
- } else {
- // Did not find the class - keep the inner class name as is.
- // TODO(b/110085899): Warn about missing classes in signatures?
- renamedSignature.append(name);
- }
- return type;
- }
-
- @Override
- public void start() {
- renamedSignature = new StringBuilder();
- }
-
- @Override
- public void stop() {
- // nothing to do
- }
- }
}
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 af62b23..14788ba 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.features.FeatureSplitConfiguration;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexDefinition;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexItemFactory;
@@ -57,7 +56,6 @@
import com.google.common.collect.Sets;
import java.io.IOException;
import java.io.PrintStream;
-import java.lang.reflect.GenericSignatureFormatError;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
@@ -911,31 +909,6 @@
}
}
- public void warningInvalidSignature(
- DexDefinition item, Origin origin, String signature, GenericSignatureFormatError e) {
- StringBuilder message = new StringBuilder("Invalid signature '");
- message.append(signature);
- message.append("' for ");
- if (item.isDexClass()) {
- message.append("class ");
- message.append((item.asDexClass()).getType().toSourceString());
- } else if (item.isDexEncodedField()) {
- message.append("field ");
- message.append(item.toSourceString());
- } else {
- assert item.isDexEncodedMethod();
- message.append("method ");
- message.append(item.toSourceString());
- }
- message.append(".");
- message.append(System.lineSeparator());
- message.append("Signature is ignored and will not be present in the output.");
- message.append(System.lineSeparator());
- message.append("Parser error: ");
- message.append(e.getMessage());
- reporter.warning(new StringDiagnostic(message.toString(), origin));
- }
-
public boolean printWarnings() {
boolean printed = false;
boolean printOutdatedToolchain = false;
diff --git a/src/main/java/com/android/tools/r8/utils/PredicateUtils.java b/src/main/java/com/android/tools/r8/utils/PredicateUtils.java
index 880da5e..f219259 100644
--- a/src/main/java/com/android/tools/r8/utils/PredicateUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/PredicateUtils.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.utils;
+import java.util.function.Function;
import java.util.function.Predicate;
public class PredicateUtils {
@@ -20,4 +21,8 @@
public static <T> Predicate<T> not(Predicate<T> predicate) {
return t -> !predicate.test(t);
}
+
+ public static <T, R> Predicate<T> isNull(Function<T, R> func) {
+ return t -> func.apply(t) == null;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/ClassSignatureTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/ClassSignatureTest.java
index cd057d2..eb76047 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/ClassSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/ClassSignatureTest.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.graph.genericsignature;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static com.android.tools.r8.graph.GenericSignature.ClassSignature.NO_CLASS_SIGNATURE;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
@@ -171,7 +170,7 @@
Origin.unknown(),
new DexItemFactory(),
new Reporter(testDiagnosticMessages));
- assertEquals(NO_CLASS_SIGNATURE, parsed);
+ assertEquals(ClassSignature.noSignature(), parsed);
return testDiagnosticMessages;
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java b/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java
index 2f909be..20e13bf 100644
--- a/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java
+++ b/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java
@@ -55,19 +55,20 @@
"}",
"-keepattributes InnerClasses,EnclosingMethod,Signature ")
.compile()
- .inspect(inspector -> {
- String genericTypeDescriptor = "Ljava/lang/Object;";
- if (genericTypeLive) {
- ClassSubject genericType = inspector.clazz(GenericType.class);
- assertThat(genericType, isRenamed(minify));
- genericTypeDescriptor = genericType.getFinalDescriptor();
- }
- String expectedSignature = "Ljava/util/List<" + genericTypeDescriptor + ">;";
- FieldSubject list = inspector.clazz(A.class).uniqueFieldWithName("list");
- assertThat(list, isPresent());
- assertThat(list.getSignatureAnnotation(), isPresent());
- assertEquals(expectedSignature, list.getSignatureAnnotationValue());
- })
+ .inspect(
+ inspector -> {
+ String genericTypeDescriptor = "*";
+ if (genericTypeLive) {
+ ClassSubject genericType = inspector.clazz(GenericType.class);
+ assertThat(genericType, isRenamed(minify));
+ genericTypeDescriptor = genericType.getFinalDescriptor();
+ }
+ String expectedSignature = "Ljava/util/List<" + genericTypeDescriptor + ">;";
+ FieldSubject list = inspector.clazz(A.class).uniqueFieldWithName("list");
+ assertThat(list, isPresent());
+ assertThat(list.getSignatureAnnotation(), isPresent());
+ assertEquals(expectedSignature, list.getSignatureAnnotationValue());
+ })
.run(mainClass)
.assertSuccess();
}
diff --git a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
index adf7ba7..e945182 100644
--- a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.naming.signature;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -71,18 +70,13 @@
}
@Test
- public void testR8WithAssertEnabled() {
- // TODO(b/154793333): Enable assertions always when resolved.
- assertThrows(
- AssertionError.class,
- () -> {
- test(
- testForR8(parameters.getBackend())
- .addKeepRules("-dontobfuscate")
- .addOptionsModification(
- internalOptions ->
- internalOptions.testing.assertConsistentRenamingOfSignature = true));
- });
+ public void testR8WithAssertEnabled() throws Exception {
+ test(
+ testForR8(parameters.getBackend())
+ .addKeepRules("-dontobfuscate")
+ .addOptionsModification(
+ internalOptions ->
+ internalOptions.testing.assertConsistentRenamingOfSignature = true));
}
private void test(R8TestBuilder<?> builder) throws Exception {