Add lookupMethod and and lookupField to ClassResult element

When retracing with regular expressions, a retraced string is a unique
combination of class, methodname, line etc. In this way, having
lookupMethod and lookupField on class element is natural.

Change-Id: I9cf50a511134f55a3af6ad746576c0b5ead131d9
diff --git a/src/main/java/com/android/tools/r8/retrace/Result.java b/src/main/java/com/android/tools/r8/retrace/Result.java
index a8e3903..2940b12 100644
--- a/src/main/java/com/android/tools/r8/retrace/Result.java
+++ b/src/main/java/com/android/tools/r8/retrace/Result.java
@@ -10,5 +10,5 @@
 @Keep
 public abstract class Result<R, RR extends Result<R, RR>> {
 
-  public abstract RR apply(Consumer<R> resultConsumer);
+  public abstract RR forEach(Consumer<R> resultConsumer);
 }
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 19bc557..ff196c1 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceBaseImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceBaseImpl.java
@@ -44,7 +44,7 @@
   public String retraceSourceFile(ClassReference classReference, String sourceFile) {
     Box<String> retracedSourceFile = new Box<>();
     retrace(classReference)
-        .apply(element -> retracedSourceFile.set(element.retraceSourceFile(sourceFile, this)));
+        .forEach(element -> retracedSourceFile.set(element.retraceSourceFile(sourceFile, this)));
     return retracedSourceFile.get();
   }
 
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 a0d5076..ee21fd2 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
@@ -15,6 +15,7 @@
 import java.util.List;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
+import java.util.stream.Stream;
 
 @Keep
 public class RetraceClassResult extends Result<Element, RetraceClassResult> {
@@ -63,7 +64,7 @@
       BiFunction<ClassNamingForNameMapper, String, T> lookupFunction,
       ResultConstructor<T, R> constructor) {
     Box<R> elementBox = new Box<>();
-    apply(
+    forEach(
         element -> {
           assert !elementBox.isSet();
           T mappedRangesForT = null;
@@ -79,13 +80,17 @@
     return mapper != null;
   }
 
-  @Override
-  public RetraceClassResult apply(Consumer<Element> resultConsumer) {
-    resultConsumer.accept(
+  Stream<Element> stream() {
+    return Stream.of(
         new Element(
             this,
             mapper == null ? obfuscatedReference : Reference.classFromTypeName(mapper.originalName),
             mapper));
+  }
+
+  @Override
+  public RetraceClassResult forEach(Consumer<Element> resultConsumer) {
+    stream().forEach(resultConsumer);
     return this;
   }
 
@@ -120,5 +125,39 @@
       return retraceBase.retraceSourceFile(
           classResult.obfuscatedReference, fileName, classReference, mapper != null);
     }
+
+    public RetraceFieldResult lookupField(String fieldName) {
+      return lookup(
+          fieldName,
+          (mapper, name) -> {
+            List<MemberNaming> memberNamings = mapper.mappedNamingsByName.get(name);
+            if (memberNamings == null || memberNamings.isEmpty()) {
+              return null;
+            }
+            return memberNamings;
+          },
+          RetraceFieldResult::new);
+    }
+
+    public RetraceMethodResult lookupMethod(String methodName) {
+      return lookup(
+          methodName,
+          (mapper, name) -> {
+            MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(name);
+            if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
+              return null;
+            }
+            return mappedRanges;
+          },
+          RetraceMethodResult::new);
+    }
+
+    private <T, R> R lookup(
+        String name,
+        BiFunction<ClassNamingForNameMapper, String, T> lookupFunction,
+        ResultConstructor<T, R> constructor) {
+      return constructor.create(
+          this, mapper != null ? lookupFunction.apply(mapper, name) : null, name);
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
index 6e0d232..69a561a 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
@@ -13,6 +13,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.function.Consumer;
+import java.util.stream.Stream;
 
 @Keep
 public class RetraceFieldResult extends Result<RetraceFieldResult.Element, RetraceFieldResult> {
@@ -45,29 +46,34 @@
     return memberNamings.size() > 1;
   }
 
-  @Override
-  public RetraceFieldResult apply(Consumer<Element> resultConsumer) {
-    if (hasRetraceResult()) {
-      assert !memberNamings.isEmpty();
-      for (MemberNaming memberNaming : memberNamings) {
-        assert memberNaming.isFieldNaming();
-        FieldSignature fieldSignature = memberNaming.getOriginalSignature().asFieldSignature();
-        resultConsumer.accept(
-            new Element(
-                this,
-                classElement,
-                Reference.field(
-                    classElement.getClassReference(),
-                    fieldSignature.name,
-                    Reference.typeFromTypeName(fieldSignature.type))));
-      }
-    } else {
-      resultConsumer.accept(
+  Stream<Element> stream() {
+    if (!hasRetraceResult()) {
+      return Stream.of(
           new Element(
               this,
               classElement,
               new UnknownFieldReference(classElement.getClassReference(), obfuscatedName)));
     }
+    assert !memberNamings.isEmpty();
+    return memberNamings.stream()
+        .map(
+            memberNaming -> {
+              assert memberNaming.isFieldNaming();
+              FieldSignature fieldSignature =
+                  memberNaming.getOriginalSignature().asFieldSignature();
+              return new Element(
+                  this,
+                  classElement,
+                  Reference.field(
+                      classElement.getClassReference(),
+                      fieldSignature.name,
+                      Reference.typeFromTypeName(fieldSignature.type)));
+            });
+  }
+
+  @Override
+  public RetraceFieldResult forEach(Consumer<Element> resultConsumer) {
+    stream().forEach(resultConsumer);
     return this;
   }
 
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 e727a6a..77b4761 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
@@ -18,6 +18,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.stream.Stream;
 
 @Keep
 public class RetraceMethodResult extends Result<RetraceMethodResult.Element, RetraceMethodResult> {
@@ -85,40 +86,45 @@
         classElement, new MappedRangesOfName(narrowedRanges), obfuscatedName);
   }
 
-  @Override
-  public RetraceMethodResult apply(Consumer<Element> resultConsumer) {
-    if (hasRetraceResult()) {
-      for (MappedRange mappedRange : mappedRanges.getMappedRanges()) {
-        MethodSignature signature = mappedRange.signature;
-        ClassReference holder =
-            mappedRange.signature.isQualified()
-                ? Reference.classFromDescriptor(
-                    DescriptorUtils.javaTypeToDescriptor(
-                        mappedRange.signature.toHolderFromQualified()))
-                : classElement.getClassReference();
-        List<TypeReference> formalTypes = new ArrayList<>(signature.parameters.length);
-        for (String parameter : signature.parameters) {
-          formalTypes.add(Reference.typeFromTypeName(parameter));
-        }
-        TypeReference returnType =
-            Reference.returnTypeFromDescriptor(
-                DescriptorUtils.javaTypeToDescriptor(signature.type));
-        MethodReference retracedMethod =
-            Reference.method(
-                holder,
-                signature.isQualified() ? signature.toUnqualifiedName() : signature.name,
-                formalTypes,
-                returnType);
-        resultConsumer.accept(new Element(this, classElement, retracedMethod, mappedRange));
-      }
-    } else {
-      resultConsumer.accept(
+  Stream<Element> stream() {
+    if (!hasRetraceResult()) {
+      return Stream.of(
           new Element(
               this,
               classElement,
               new UnknownMethodReference(classElement.getClassReference(), obfuscatedName),
               null));
     }
+    return mappedRanges.getMappedRanges().stream()
+        .map(
+            mappedRange -> {
+              MethodSignature signature = mappedRange.signature;
+              ClassReference holder =
+                  mappedRange.signature.isQualified()
+                      ? Reference.classFromDescriptor(
+                          DescriptorUtils.javaTypeToDescriptor(
+                              mappedRange.signature.toHolderFromQualified()))
+                      : classElement.getClassReference();
+              List<TypeReference> formalTypes = new ArrayList<>(signature.parameters.length);
+              for (String parameter : signature.parameters) {
+                formalTypes.add(Reference.typeFromTypeName(parameter));
+              }
+              TypeReference returnType =
+                  Reference.returnTypeFromDescriptor(
+                      DescriptorUtils.javaTypeToDescriptor(signature.type));
+              MethodReference retracedMethod =
+                  Reference.method(
+                      holder,
+                      signature.isQualified() ? signature.toUnqualifiedName() : signature.name,
+                      formalTypes,
+                      returnType);
+              return new Element(this, classElement, retracedMethod, mappedRange);
+            });
+  }
+
+  @Override
+  public RetraceMethodResult forEach(Consumer<Element> resultConsumer) {
+    stream().forEach(resultConsumer);
     return this;
   }
 
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 1dd8cec..1f4fa43 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceStackTrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceStackTrace.java
@@ -230,7 +230,7 @@
       List<StackTraceLine> exceptionLines = new ArrayList<>();
       retraceBase
           .retrace(Reference.classFromTypeName(exceptionClass))
-          .apply(
+          .forEach(
               element ->
                   exceptionLines.add(
                       new ExceptionLine(
@@ -369,7 +369,7 @@
               .retrace(classReference)
               .lookupMethod(method)
               .narrowByLine(linePosition)
-              .apply(
+              .forEach(
                   methodElement -> {
                     MethodReference methodReference = methodElement.getMethodReference();
                     lines.add(