Implement slowCompareTo(NamingLens) with visitor.
Bug: 171867022
Change-Id: I430632330fc5e7aeb37aaa8a0ffa14d9fa7909ad
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index 755ff8fe..5f95369 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -5,19 +5,17 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralAccept;
-import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Collections;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
-public class DexField extends DexMember<DexEncodedField, DexField>
- implements StructuralItem<DexField> {
+public class DexField extends DexMember<DexEncodedField, DexField> {
public final DexType type;
@@ -144,16 +142,8 @@
}
@Override
- public int slowCompareTo(DexField other, NamingLens namingLens) {
- int result = holder.slowCompareTo(other.holder, namingLens);
- if (result != 0) {
- return result;
- }
- result = namingLens.lookupName(this).compareTo(namingLens.lookupName(other));
- if (result != 0) {
- return result;
- }
- return type.slowCompareTo(other.type, namingLens);
+ public void acceptCompareTo(DexField other, CompareToVisitor visitor) {
+ visitor.visitDexField(this, other);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index 6a07b34..249e77e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -5,12 +5,11 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralAccept;
-import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.ArrayList;
import java.util.List;
@@ -18,8 +17,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
-public class DexMethod extends DexMember<DexEncodedMethod, DexMethod>
- implements StructuralItem<DexMethod> {
+public class DexMethod extends DexMember<DexEncodedMethod, DexMethod> {
public final DexProto proto;
@@ -47,6 +45,11 @@
return this;
}
+ @Override
+ public void acceptCompareTo(DexMethod other, CompareToVisitor visitor) {
+ visitor.visitDexMethod(this, other);
+ }
+
public DexType getHolderType() {
return holder;
}
@@ -199,19 +202,6 @@
}
@Override
- public int slowCompareTo(DexMethod other, NamingLens namingLens) {
- int result = holder.slowCompareTo(other.holder, namingLens);
- if (result != 0) {
- return result;
- }
- result = namingLens.lookupName(this).compareTo(namingLens.lookupName(other));
- if (result != 0) {
- return result;
- }
- return proto.slowCompareTo(other.proto, namingLens);
- }
-
- @Override
public boolean match(DexMethod method) {
return method.name == name && method.proto == proto;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
index f34c70c..55522d5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -8,12 +8,14 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.structural.StructuralAccept;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Objects;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
-public class DexMethodHandle extends IndexedDexItem implements
- PresortedComparable<DexMethodHandle> {
+public class DexMethodHandle extends IndexedDexItem
+ implements PresortedComparable<DexMethodHandle> {
public enum MethodHandleType {
STATIC_PUT((short) 0x00),
@@ -313,31 +315,21 @@
}
@Override
- public int compareTo(DexMethodHandle other) {
- int result = type.getValue() - other.type.getValue();
- if (result == 0) {
- if (isFieldHandle()) {
- result = asField().compareTo(other.asField());
- } else {
- assert isMethodHandle();
- result = asMethod().compareTo(other.asMethod());
- }
- }
- return result;
+ public DexMethodHandle self() {
+ return this;
}
@Override
- public int slowCompareTo(DexMethodHandle other, NamingLens namingLens) {
- int result = type.getValue() - other.type.getValue();
- if (result == 0) {
- if (isFieldHandle()) {
- result = asField().slowCompareTo(other.asField(), namingLens);
- } else {
- assert isMethodHandle();
- result = asMethod().slowCompareTo(other.asMethod(), namingLens);
- }
- }
- return result;
+ public StructuralAccept<DexMethodHandle> getStructuralAccept() {
+ return DexMethodHandle::specify;
+ }
+
+ private static void specify(StructuralSpecification<DexMethodHandle, ?> spec) {
+ spec.withInt(m -> m.type.getValue())
+ .withConditionalItem(DexMethodHandle::isFieldHandle, DexMethodHandle::asField)
+ .withConditionalItem(DexMethodHandle::isMethodHandle, DexMethodHandle::asMethod)
+ .withBool(m -> m.isInterface)
+ .withItem(m -> m.rewrittenTarget);
}
public Handle toAsmHandle(NamingLens lens) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java
index 5ec1cfb..2caf3a7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProto.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -6,14 +6,12 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.structural.StructuralAccept;
-import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.function.Consumer;
-public class DexProto extends IndexedDexItem
- implements PresortedComparable<DexProto>, StructuralItem<DexProto> {
+public class DexProto extends IndexedDexItem implements PresortedComparable<DexProto> {
public static final DexProto SENTINEL = new DexProto(null, null, null);
@@ -28,8 +26,10 @@
}
private static void accept(StructuralSpecification<DexProto, ?> spec) {
- // TODO(b/172206529): Consider removing shorty.
- spec.withItem(p1 -> p1.shorty).withItem(DexProto::getReturnType).withItem(p -> p.parameters);
+ spec.withItem(DexProto::getReturnType)
+ .withItem(p -> p.parameters)
+ // TODO(b/172206529): Consider removing shorty.
+ .withItem(p1 -> p1.shorty);
}
@Override
@@ -106,15 +106,6 @@
}
@Override
- public int slowCompareTo(DexProto other, NamingLens namingLens) {
- int result = returnType.slowCompareTo(other.returnType, namingLens);
- if (result == 0) {
- result = parameters.slowCompareTo(other.parameters, namingLens);
- }
- return result;
- }
-
- @Override
public String toSmaliString() {
return toDescriptorString();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index 595e8d3..9fde6f0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.IdentifierUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -14,13 +13,11 @@
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralAccept;
-import com.android.tools.r8.utils.structural.StructuralItem;
import java.io.UTFDataFormatException;
import java.util.Arrays;
import java.util.NoSuchElementException;
-public class DexString extends IndexedDexItem
- implements PresortedComparable<DexString>, StructuralItem<DexString> {
+public class DexString extends IndexedDexItem implements PresortedComparable<DexString> {
public static final DexString[] EMPTY_ARRAY = {};
private static final int ARRAY_CHARACTER = '[';
@@ -299,12 +296,6 @@
}
}
- @Override
- public int slowCompareTo(DexString other, NamingLens lens) {
- // The naming lens cannot affect strings.
- return compareTo(other);
- }
-
private static boolean isValidClassDescriptor(String string) {
if (string.length() < 3
|| string.charAt(0) != 'L'
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 3dd7133..b757e40 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -20,7 +20,6 @@
import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
-import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -28,7 +27,6 @@
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralAccept;
-import com.android.tools.r8.utils.structural.StructuralItem;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.List;
@@ -38,8 +36,7 @@
import java.util.function.Function;
import java.util.function.Predicate;
-public class DexType extends DexReference
- implements PresortedComparable<DexType>, StructuralItem<DexType> {
+public class DexType extends DexReference implements PresortedComparable<DexType> {
public static final DexType[] EMPTY_ARRAY = {};
// Bundletool is merging classes that may originate from a build with an old version of R8.
@@ -229,13 +226,6 @@
return this;
}
- @Override
- public int slowCompareTo(DexType other, NamingLens namingLens) {
- DexString thisDescriptor = namingLens.lookupDescriptor(this);
- DexString otherDescriptor = namingLens.lookupDescriptor(other);
- return thisDescriptor.slowCompareTo(otherDescriptor, namingLens);
- }
-
public boolean isPrimitiveType() {
return DescriptorUtils.isPrimitiveType((char) descriptor.content[0]);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index 28ff803..a641039 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -118,38 +117,6 @@
return builder.toString();
}
- public int slowCompareTo(DexTypeList other) {
- for (int i = 0; i <= Math.min(values.length, other.values.length); i++) {
- if (i == values.length) {
- return i == other.values.length ? 0 : -1;
- } else if (i == other.values.length) {
- return 1;
- } else {
- int result = values[i].compareTo(other.values[i]);
- if (result != 0) {
- return result;
- }
- }
- }
- throw new Unreachable();
- }
-
- public int slowCompareTo(DexTypeList other, NamingLens namingLens) {
- for (int i = 0; i <= Math.min(values.length, other.values.length); i++) {
- if (i == values.length) {
- return i == other.values.length ? 0 : -1;
- } else if (i == other.values.length) {
- return 1;
- } else {
- int result = values[i].slowCompareTo(other.values[i], namingLens);
- if (result != 0) {
- return result;
- }
- }
- }
- throw new Unreachable();
- }
-
@Override
public Iterator<DexType> iterator() {
return Iterators.forArray(values);
diff --git a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
index 82e53c3..623e2f4 100644
--- a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
+++ b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
@@ -4,8 +4,12 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.structural.CompareToVisitorWithNamingLens;
+import com.android.tools.r8.utils.structural.StructuralItem;
-public interface PresortedComparable<T> extends Comparable<T> {
+public interface PresortedComparable<T extends PresortedComparable<T>> extends StructuralItem<T> {
- int slowCompareTo(T other, NamingLens namingLens);
+ default int slowCompareTo(T other, NamingLens lens) {
+ return CompareToVisitorWithNamingLens.run(self(), other, lens, StructuralItem::acceptCompareTo);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java
index 782324f..832d172 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.structural;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
@@ -22,6 +24,14 @@
public abstract void visitDexTypeList(DexTypeList types1, DexTypeList types2);
+ public void visitDexField(DexField field1, DexField field2) {
+ visit(field1, field2, field1.getStructuralAccept());
+ }
+
+ public void visitDexMethod(DexMethod method1, DexMethod method2) {
+ visit(method1, method2, method1.getStructuralAccept());
+ }
+
public abstract <S> void visit(S item1, S item2, StructuralAccept<S> accept);
@Deprecated
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java
new file mode 100644
index 0000000..5ef5e72
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java
@@ -0,0 +1,172 @@
+// 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.utils.structural;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
+import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
+import java.util.Comparator;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
+
+public class CompareToVisitorWithNamingLens extends CompareToVisitor {
+
+ public static <T> int run(T item1, T item2, NamingLens namingLens, StructuralAccept<T> visit) {
+ return run(item1, item2, namingLens, (i1, i2, visitor) -> visitor.visit(i1, i2, visit));
+ }
+
+ public static <T> int run(
+ T item1, T item2, NamingLens namingLens, CompareToAccept<T> compareToAccept) {
+ CompareToVisitorWithNamingLens state = new CompareToVisitorWithNamingLens(namingLens);
+ compareToAccept.accept(item1, item2, state);
+ return state.order;
+ }
+
+ private final NamingLens namingLens;
+ private int order = 0;
+
+ public CompareToVisitorWithNamingLens(NamingLens namingLens) {
+ this.namingLens = namingLens;
+ }
+
+ @Override
+ public void visitBool(boolean value1, boolean value2) {
+ if (order == 0) {
+ order = Boolean.compare(value1, value2);
+ }
+ }
+
+ @Override
+ public void visitInt(int value1, int value2) {
+ if (order == 0) {
+ order = Integer.compare(value1, value2);
+ }
+ }
+
+ @Override
+ public <S> void visit(S item1, S item2, Comparator<S> comparator) {
+ if (order == 0) {
+ order = comparator.compare(item1, item2);
+ }
+ }
+
+ @Override
+ public <S> void visit(S item1, S item2, StructuralAccept<S> accept) {
+ if (order == 0) {
+ accept.accept(new ItemSpecification<>(item1, item2, this));
+ }
+ }
+
+ @Override
+ public void visitDexString(
+ DexString string1, DexString string2, Comparator<DexString> comparator) {
+ if (order == 0) {
+ order = comparator.compare(string1, string2);
+ }
+ }
+
+ @Override
+ public void visitDexType(DexType type1, DexType type2) {
+ if (order == 0) {
+ namingLens.lookupDescriptor(type1).acceptCompareTo(namingLens.lookupDescriptor(type2), this);
+ }
+ }
+
+ @Override
+ public void visitDexField(DexField field1, DexField field2) {
+ if (order == 0) {
+ field1.holder.acceptCompareTo(field2.holder, this);
+ if (order == 0) {
+ namingLens.lookupName(field1).acceptCompareTo(namingLens.lookupName(field2), this);
+ if (order == 0) {
+ field1.type.acceptCompareTo(field2.type, this);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visitDexMethod(DexMethod method1, DexMethod method2) {
+ if (order == 0) {
+ method1.holder.acceptCompareTo(method2.holder, this);
+ if (order == 0) {
+ namingLens.lookupName(method1).acceptCompareTo(namingLens.lookupName(method2), this);
+ if (order == 0) {
+ method1.proto.acceptCompareTo(method2.proto, this);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visitDexTypeList(DexTypeList types1, DexTypeList types2) {
+ // Comparison is lexicographic with comparisons between items prior to the length of the lists.
+ if (order == 0) {
+ int length = Math.min(types1.size(), types2.size());
+ for (int i = 0; i < length && order == 0; i++) {
+ visitDexType(types1.values[i], types2.values[i]);
+ }
+ if (order == 0) {
+ visitInt(types1.size(), types2.size());
+ }
+ }
+ }
+
+ private static class ItemSpecification<T>
+ extends StructuralSpecification<T, ItemSpecification<T>> {
+
+ private final CompareToVisitorWithNamingLens parent;
+ private final T item1;
+ private final T item2;
+
+ private ItemSpecification(T item1, T item2, CompareToVisitorWithNamingLens parent) {
+ this.item1 = item1;
+ this.item2 = item2;
+ this.parent = parent;
+ }
+
+ @Override
+ public ItemSpecification<T> withAssert(Predicate<T> predicate) {
+ assert predicate.test(item1);
+ assert predicate.test(item2);
+ return this;
+ }
+
+ @Override
+ public ItemSpecification<T> withBool(Predicate<T> getter) {
+ parent.visitBool(getter.test(item1), getter.test(item2));
+ return this;
+ }
+
+ @Override
+ public ItemSpecification<T> withInt(ToIntFunction<T> getter) {
+ parent.visitInt(getter.applyAsInt(item1), getter.applyAsInt(item2));
+ return this;
+ }
+
+ @Override
+ public <S> ItemSpecification<T> withConditionalCustomItem(
+ Predicate<T> predicate,
+ Function<T, S> getter,
+ CompareToAccept<S> compare,
+ HashingAccept<S> hasher) {
+ if (parent.order == 0) {
+ boolean test1 = predicate.test(item1);
+ boolean test2 = predicate.test(item2);
+ if (test1 && test2) {
+ compare.accept(getter.apply(item1), getter.apply(item2), parent);
+ } else {
+ parent.visitBool(test1, test2);
+ }
+ }
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java
index 7baa091..39d6c7e 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java
@@ -125,10 +125,19 @@
}
@Override
- public <S> ItemSpecification<T> withCustomItem(
- Function<T, S> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
+ protected <S> ItemSpecification<T> withConditionalCustomItem(
+ Predicate<T> predicate,
+ Function<T, S> getter,
+ CompareToAccept<S> compare,
+ HashingAccept<S> hasher) {
if (parent.order == 0) {
- compare.accept(getter.apply(item1), getter.apply(item2), parent);
+ boolean test1 = predicate.test(item1);
+ boolean test2 = predicate.test(item2);
+ if (test1 && test2) {
+ compare.accept(getter.apply(item1), getter.apply(item2), parent);
+ } else {
+ parent.visitBool(test1, test2);
+ }
}
return this;
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
index af354d0..ab75fb4 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
@@ -56,11 +56,17 @@
}
@Override
- public <S> HashCodeVisitor<T> withCustomItem(
- Function<T, S> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
- S member = getter.apply(item);
- // Use the value 1 for the null-member case such that a different hash is obtained for
- // {null, null} and {null}.
- return amend(member == null ? 1 : member.hashCode());
+ protected <S> HashCodeVisitor<T> withConditionalCustomItem(
+ Predicate<T> predicate,
+ Function<T, S> getter,
+ CompareToAccept<S> compare,
+ HashingAccept<S> hasher) {
+ if (predicate.test(item)) {
+ return amend(getter.apply(item).hashCode());
+ } else {
+ // Use the value 1 for the failing-predicate case such that a different hash is obtained for
+ // eg, {null, null} and {null}.
+ return amend(1);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
index b64fa45..2036b1b 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
@@ -100,9 +100,17 @@
}
@Override
- public <S> ItemSpecification<T> withCustomItem(
- Function<T, S> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
- hasher.accept(getter.apply(item), parent);
+ protected <S> ItemSpecification<T> withConditionalCustomItem(
+ Predicate<T> predicate,
+ Function<T, S> getter,
+ CompareToAccept<S> compare,
+ HashingAccept<S> hasher) {
+ boolean test = predicate.test(item);
+ // Always hash the predicate result to distinguish, eg, {null, null} and {null}.
+ parent.visitBool(test);
+ if (test) {
+ hasher.accept(getter.apply(item), parent);
+ }
return this;
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
index 0c2eea4..bb8f7c7 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
@@ -20,8 +20,16 @@
* <p>It is preferable to use withStructuralItem.
*/
@Deprecated
- public abstract <S> V withCustomItem(
- Function<T, S> getter, CompareToAccept<S> compare, HashingAccept<S> hasher);
+ public final <S> V withCustomItem(
+ Function<T, S> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
+ return withConditionalCustomItem(t -> true, getter, compare, hasher);
+ }
+
+ protected abstract <S> V withConditionalCustomItem(
+ Predicate<T> predicate,
+ Function<T, S> getter,
+ CompareToAccept<S> compare,
+ HashingAccept<S> hasher);
/**
* Specification for a "specified" item.
@@ -29,8 +37,17 @@
* <p>Using this the visiting methods are could based on the implementation of the Specified
* interface.
*/
- public <S extends StructuralItem<S>> V withItem(Function<T, S> getter) {
- return withCustomItem(getter, S::acceptCompareTo, S::acceptHashing);
+ public final <S extends StructuralItem<S>> V withItem(Function<T, S> getter) {
+ return withConditionalItem(t -> true, getter);
+ }
+
+ final <S extends StructuralItem<S>> V withNullableItem(Function<T, S> getter) {
+ return withConditionalItem(s -> getter.apply(s) != null, getter);
+ }
+
+ public final <S extends StructuralItem<S>> V withConditionalItem(
+ Predicate<T> predicate, Function<T, S> getter) {
+ return withConditionalCustomItem(predicate, getter, S::acceptCompareTo, S::acceptHashing);
}
/**