Merge "Fix a bug in DexAnnotationDirectory.equals."
diff --git a/src/main/java/com/android/tools/r8/graph/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/graph/ClassAndMemberPublicizer.java
index 3c3c2b9..9583e9c 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassAndMemberPublicizer.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassAndMemberPublicizer.java
@@ -4,19 +4,6 @@
 package com.android.tools.r8.graph;
 
 public abstract class ClassAndMemberPublicizer {
-
-  private static void publicizeAllMethods(DexEncodedMethod[] methods) {
-    for (DexEncodedMethod method : methods) {
-      method.accessFlags.promoteNonPrivateToPublic();
-    }
-  }
-
-  private static void publicizeAllFields(DexEncodedField[] fields) {
-    for (DexEncodedField field : fields) {
-      field.accessFlags.promoteToPublic();
-    }
-  }
-
   /**
    * Marks all package private and protected methods and fields as public.
    * <p>
@@ -25,10 +12,8 @@
   public static DexApplication run(DexApplication application) {
     for (DexClass clazz : application.classes()) {
       clazz.accessFlags.promoteToPublic();
-      publicizeAllFields(clazz.staticFields());
-      publicizeAllFields(clazz.instanceFields());
-      publicizeAllMethods(clazz.directMethods());
-      publicizeAllMethods(clazz.virtualMethods());
+      clazz.forEachMethod( method -> method.accessFlags.promoteNonPrivateToPublic());
+      clazz.forEachField( field -> field.accessFlags.promoteToPublic());
     }
     return application;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
index 6887d0f..4277324 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
@@ -48,10 +48,6 @@
     }
   }
 
-  public DexProgramClass getDexProgramClass() {
-    return clazz;
-  }
-
   public DexAnnotationSet getClazzAnnotations() {
     return clazz.annotations;
   }
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 5b1b0f3..b28f06c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -95,6 +95,15 @@
     return result;
   }
 
+  public void forEachField(Consumer<DexEncodedField> consumer) {
+    for (DexEncodedField field : staticFields()) {
+      consumer.accept(field);
+    }
+    for (DexEncodedField field : instanceFields()) {
+      consumer.accept(field);
+    }
+  }
+
   public DexEncodedField[] staticFields() {
     return MoreObjects.firstNonNull(staticFields, NO_FIELDS);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 36d732d..04e34a5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -50,95 +50,95 @@
   public static final DexType catchAllType = new DexType(new DexString("CATCH_ALL"));
   private static final Set<DexItem> internalSentinels = ImmutableSet.of(catchAllType);
 
-  public DexString booleanDescriptor = createString("Z");
-  public DexString byteDescriptor = createString("B");
-  public DexString charDescriptor = createString("C");
-  public DexString doubleDescriptor = createString("D");
-  public DexString floatDescriptor = createString("F");
-  public DexString intDescriptor = createString("I");
-  public DexString longDescriptor = createString("J");
-  public DexString shortDescriptor = createString("S");
-  public DexString voidDescriptor = createString("V");
+  public final DexString booleanDescriptor = createString("Z");
+  public final DexString byteDescriptor = createString("B");
+  public final DexString charDescriptor = createString("C");
+  public final DexString doubleDescriptor = createString("D");
+  public final DexString floatDescriptor = createString("F");
+  public final DexString intDescriptor = createString("I");
+  public final DexString longDescriptor = createString("J");
+  public final DexString shortDescriptor = createString("S");
+  public final DexString voidDescriptor = createString("V");
 
-  public DexString boxedBooleanDescriptor = createString("Ljava/lang/Boolean;");
-  public DexString boxedByteDescriptor = createString("Ljava/lang/Byte;");
-  public DexString boxedCharDescriptor = createString("Ljava/lang/Character;");
-  public DexString boxedDoubleDescriptor = createString("Ljava/lang/Double;");
-  public DexString boxedFloatDescriptor = createString("Ljava/lang/Float;");
-  public DexString boxedIntDescriptor = createString("Ljava/lang/Integer;");
-  public DexString boxedLongDescriptor = createString("Ljava/lang/Long;");
-  public DexString boxedShortDescriptor = createString("Ljava/lang/Short;");
-  public DexString boxedNumberDescriptor = createString("Ljava/lang/Number;");
+  public final DexString boxedBooleanDescriptor = createString("Ljava/lang/Boolean;");
+  public final DexString boxedByteDescriptor = createString("Ljava/lang/Byte;");
+  public final DexString boxedCharDescriptor = createString("Ljava/lang/Character;");
+  public final DexString boxedDoubleDescriptor = createString("Ljava/lang/Double;");
+  public final DexString boxedFloatDescriptor = createString("Ljava/lang/Float;");
+  public final DexString boxedIntDescriptor = createString("Ljava/lang/Integer;");
+  public final DexString boxedLongDescriptor = createString("Ljava/lang/Long;");
+  public final DexString boxedShortDescriptor = createString("Ljava/lang/Short;");
+  public final DexString boxedNumberDescriptor = createString("Ljava/lang/Number;");
 
-  public DexString unboxBooleanMethodName = createString("booleanValue");
-  public DexString unboxByteMethodName = createString("byteValue");
-  public DexString unboxCharMethodName = createString("charValue");
-  public DexString unboxShortMethodName = createString("shortValue");
-  public DexString unboxIntMethodName = createString("intValue");
-  public DexString unboxLongMethodName = createString("longValue");
-  public DexString unboxFloatMethodName = createString("floatValue");
-  public DexString unboxDoubleMethodName = createString("doubleValue");
+  public final DexString unboxBooleanMethodName = createString("booleanValue");
+  public final DexString unboxByteMethodName = createString("byteValue");
+  public final DexString unboxCharMethodName = createString("charValue");
+  public final DexString unboxShortMethodName = createString("shortValue");
+  public final DexString unboxIntMethodName = createString("intValue");
+  public final DexString unboxLongMethodName = createString("longValue");
+  public final DexString unboxFloatMethodName = createString("floatValue");
+  public final DexString unboxDoubleMethodName = createString("doubleValue");
 
-  public DexString valueOfMethodName = createString("valueOf");
+  public final DexString valueOfMethodName = createString("valueOf");
 
-  public DexString getClassMethodName = createString("getClass");
-  public DexString ordinalMethodName = createString("ordinal");
+  public final DexString getClassMethodName = createString("getClass");
+  public final DexString ordinalMethodName = createString("ordinal");
   public final DexString desiredAssertionStatusMethodName = createString("desiredAssertionStatus");
   public final DexString assertionsDisabled = createString("$assertionsDisabled");
 
-  public DexString stringDescriptor = createString("Ljava/lang/String;");
-  public DexString objectDescriptor = createString("Ljava/lang/Object;");
-  public DexString classDescriptor = createString("Ljava/lang/Class;");
-  public DexString enumDescriptor = createString("Ljava/lang/Enum;");
-  public DexString annotationDescriptor = createString("Ljava/lang/annotation/Annotation;");
-  public DexString throwableDescriptor = createString("Ljava/lang/Throwable;");
-  public DexString objectsDescriptor = createString("Ljava/util/Objects;");
+  public final DexString stringDescriptor = createString("Ljava/lang/String;");
+  public final DexString objectDescriptor = createString("Ljava/lang/Object;");
+  public final DexString classDescriptor = createString("Ljava/lang/Class;");
+  public final DexString enumDescriptor = createString("Ljava/lang/Enum;");
+  public final DexString annotationDescriptor = createString("Ljava/lang/annotation/Annotation;");
+  public final DexString throwableDescriptor = createString("Ljava/lang/Throwable;");
+  public final DexString objectsDescriptor = createString("Ljava/util/Objects;");
 
-  public DexString constructorMethodName = createString(Constants.INSTANCE_INITIALIZER_NAME);
-  public DexString classConstructorMethodName = createString(Constants.CLASS_INITIALIZER_NAME);
+  public final DexString constructorMethodName = createString(Constants.INSTANCE_INITIALIZER_NAME);
+  public final DexString classConstructorMethodName = createString(Constants.CLASS_INITIALIZER_NAME);
 
-  public DexString thisName = createString("this");
+  public final DexString thisName = createString("this");
 
-  private DexString charArrayDescriptor = createString("[C");
-  private DexType charArrayType = createType(charArrayDescriptor);
-  public DexString throwableArrayDescriptor = createString("[Ljava/lang/Throwable;");
+  private final DexString charArrayDescriptor = createString("[C");
+  private final DexType charArrayType = createType(charArrayDescriptor);
+  public final DexString throwableArrayDescriptor = createString("[Ljava/lang/Throwable;");
 
-  public DexType booleanType = createType(booleanDescriptor);
-  public DexType byteType = createType(byteDescriptor);
-  public DexType charType = createType(charDescriptor);
-  public DexType doubleType = createType(doubleDescriptor);
-  public DexType floatType = createType(floatDescriptor);
-  public DexType intType = createType(intDescriptor);
-  public DexType longType = createType(longDescriptor);
-  public DexType shortType = createType(shortDescriptor);
-  public DexType voidType = createType(voidDescriptor);
+  public final DexType booleanType = createType(booleanDescriptor);
+  public final DexType byteType = createType(byteDescriptor);
+  public final DexType charType = createType(charDescriptor);
+  public final DexType doubleType = createType(doubleDescriptor);
+  public final DexType floatType = createType(floatDescriptor);
+  public final DexType intType = createType(intDescriptor);
+  public final DexType longType = createType(longDescriptor);
+  public final DexType shortType = createType(shortDescriptor);
+  public final DexType voidType = createType(voidDescriptor);
 
-  public DexType boxedBooleanType = createType(boxedBooleanDescriptor);
-  public DexType boxedByteType = createType(boxedByteDescriptor);
-  public DexType boxedCharType = createType(boxedCharDescriptor);
-  public DexType boxedDoubleType = createType(boxedDoubleDescriptor);
-  public DexType boxedFloatType = createType(boxedFloatDescriptor);
-  public DexType boxedIntType = createType(boxedIntDescriptor);
-  public DexType boxedLongType = createType(boxedLongDescriptor);
-  public DexType boxedShortType = createType(boxedShortDescriptor);
-  public DexType boxedNumberType = createType(boxedNumberDescriptor);
+  public final DexType boxedBooleanType = createType(boxedBooleanDescriptor);
+  public final DexType boxedByteType = createType(boxedByteDescriptor);
+  public final DexType boxedCharType = createType(boxedCharDescriptor);
+  public final DexType boxedDoubleType = createType(boxedDoubleDescriptor);
+  public final DexType boxedFloatType = createType(boxedFloatDescriptor);
+  public final DexType boxedIntType = createType(boxedIntDescriptor);
+  public final DexType boxedLongType = createType(boxedLongDescriptor);
+  public final DexType boxedShortType = createType(boxedShortDescriptor);
+  public final DexType boxedNumberType = createType(boxedNumberDescriptor);
 
-  public DexType stringType = createType(stringDescriptor);
-  public DexType objectType = createType(objectDescriptor);
-  public DexType enumType = createType(enumDescriptor);
-  public DexType annotationType = createType(annotationDescriptor);
-  public DexType throwableType = createType(throwableDescriptor);
+  public final DexType stringType = createType(stringDescriptor);
+  public final DexType objectType = createType(objectDescriptor);
+  public final DexType enumType = createType(enumDescriptor);
+  public final DexType annotationType = createType(annotationDescriptor);
+  public final DexType throwableType = createType(throwableDescriptor);
 
-  public DexType stringBuilderType = createType("Ljava/lang/StringBuilder;");
-  public DexType stringBufferType = createType("Ljava/lang/StringBuffer;");
+  public final DexType stringBuilderType = createType("Ljava/lang/StringBuilder;");
+  public final DexType stringBufferType = createType("Ljava/lang/StringBuffer;");
 
-  public StringBuildingMethods stringBuilderMethods = new StringBuildingMethods(stringBuilderType);
-  public StringBuildingMethods stringBufferMethods = new StringBuildingMethods(stringBufferType);
-  public ObjectsMethods objectsMethods = new ObjectsMethods();
-  public ObjectMethods objectMethods = new ObjectMethods();
-  public LongMethods longMethods = new LongMethods();
-  public ThrowableMethods throwableMethods = new ThrowableMethods();
-  public ClassMethods classMethods = new ClassMethods();
+  public final StringBuildingMethods stringBuilderMethods = new StringBuildingMethods(stringBuilderType);
+  public final StringBuildingMethods stringBufferMethods = new StringBuildingMethods(stringBufferType);
+  public final ObjectsMethods objectsMethods = new ObjectsMethods();
+  public final ObjectMethods objectMethods = new ObjectMethods();
+  public final LongMethods longMethods = new LongMethods();
+  public final ThrowableMethods throwableMethods = new ThrowableMethods();
+  public final ClassMethods classMethods = new ClassMethods();
 
   // Dex system annotations.
   // See https://source.android.com/devices/tech/dalvik/dex-format.html#system-annotation
@@ -161,7 +161,7 @@
 
   public class LongMethods {
 
-    public DexMethod compare;
+    public final DexMethod compare;
 
     private LongMethods() {
       compare = createMethod(boxedLongDescriptor,
@@ -184,11 +184,11 @@
 
   public class ObjectMethods {
 
-    public DexMethod getClass;
+    public final DexMethod getClass;
 
     private ObjectMethods() {
-      getClass = createMethod(objectsDescriptor,
-          getClassMethodName, classDescriptor, new DexString[]{});
+      getClass = createMethod(objectsDescriptor, getClassMethodName, classDescriptor,
+          DexString.EMPTY_ARRAY);
     }
   }
 
@@ -208,27 +208,27 @@
 
     private ClassMethods() {
       desiredAssertionStatus = createMethod(classDescriptor,
-          desiredAssertionStatusMethodName, booleanDescriptor, new DexString[]{});
+          desiredAssertionStatusMethodName, booleanDescriptor, DexString.EMPTY_ARRAY);
     }
   }
 
 
   public class StringBuildingMethods {
 
-    public DexMethod appendBoolean;
-    public DexMethod appendChar;
-    public DexMethod appendCharArray;
-    public DexMethod appendSubCharArray;
-    public DexMethod appendCharSequence;
-    public DexMethod appendSubCharSequence;
-    public DexMethod appendInt;
-    public DexMethod appendDouble;
-    public DexMethod appendFloat;
-    public DexMethod appendLong;
-    public DexMethod appendObject;
-    public DexMethod appendString;
-    public DexMethod appendStringBuffer;
-    public DexMethod toString;
+    public final DexMethod appendBoolean;
+    public final DexMethod appendChar;
+    public final DexMethod appendCharArray;
+    public final DexMethod appendSubCharArray;
+    public final DexMethod appendCharSequence;
+    public final DexMethod appendSubCharSequence;
+    public final DexMethod appendInt;
+    public final DexMethod appendDouble;
+    public final DexMethod appendFloat;
+    public final DexMethod appendLong;
+    public final DexMethod appendObject;
+    public final DexMethod appendString;
+    public final DexMethod appendStringBuffer;
+    public final DexMethod toString;
 
     private StringBuildingMethods(DexType receiver) {
       DexType sbufType = createType(createString("Ljava/lang/StringBuffer;"));
@@ -236,7 +236,6 @@
       DexString append = createString("append");
       DexString toStringMethodName = createString("toString");
 
-
       appendBoolean = createMethod(receiver, createProto(receiver, booleanType), append);
       appendChar = createMethod(receiver, createProto(receiver, charType), append);
       appendCharArray = createMethod(receiver, createProto(receiver, charArrayType), append);
@@ -282,7 +281,7 @@
 
   synchronized private DexString canonicalizeString(String key) {
     assert key != null;
-    return strings.computeIfAbsent(key, k -> new DexString(k));
+    return strings.computeIfAbsent(key, DexString::new);
   }
 
   public DexString createString(int size, byte[] content) {
@@ -382,56 +381,31 @@
 
   public AdvanceLine createAdvanceLine(int delta) {
     synchronized (advanceLines) {
-      AdvanceLine result = advanceLines.get(delta);
-      if (result == null) {
-        result = new AdvanceLine(delta);
-        advanceLines.put(delta, result);
-      }
-      return result;
+      return advanceLines.computeIfAbsent(delta, AdvanceLine::new);
     }
   }
 
   public AdvancePC createAdvancePC(int delta) {
     synchronized (advancePCs) {
-      AdvancePC result = advancePCs.get(delta);
-      if (result == null) {
-        result = new AdvancePC(delta);
-        advancePCs.put(delta, result);
-      }
-      return result;
+      return advancePCs.computeIfAbsent(delta, AdvancePC::new);
     }
   }
 
   public Default createDefault(int value) {
     synchronized (defaults) {
-      Default result = defaults.get(value);
-      if (result == null) {
-        result = new Default(value);
-        defaults.put(value, result);
-      }
-      return result;
+      return defaults.computeIfAbsent(value, Default::new);
     }
   }
 
   public EndLocal createEndLocal(int registerNum) {
     synchronized (endLocals) {
-      EndLocal result = endLocals.get(registerNum);
-      if (result == null) {
-        result = new EndLocal(registerNum);
-        endLocals.put(registerNum, result);
-      }
-      return result;
+      return endLocals.computeIfAbsent(registerNum, EndLocal::new);
     }
   }
 
   public RestartLocal createRestartLocal(int registerNum) {
     synchronized (restartLocals) {
-      RestartLocal result = restartLocals.get(registerNum);
-      if (result == null) {
-        result = new RestartLocal(registerNum);
-        restartLocals.put(registerNum, result);
-      }
-      return result;
+      return restartLocals.computeIfAbsent(registerNum, RestartLocal::new);
     }
   }
 
@@ -445,12 +419,7 @@
 
   public SetFile createSetFile(DexString fileName) {
     synchronized (setFiles) {
-      SetFile result = setFiles.get(fileName);
-      if (result == null) {
-        result = new SetFile(fileName);
-        setFiles.put(fileName, result);
-      }
-      return result;
+      return setFiles.computeIfAbsent(fileName, SetFile::new);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index f4406c0..9c76d74 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -27,6 +27,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Call graph representation.
@@ -82,16 +83,6 @@
     }
 
     @Override
-    public int hashCode() {
-      return method.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      return this == obj;
-    }
-
-    @Override
     public String toString() {
       StringBuilder builder = new StringBuilder();
       builder.append("MethodNode for: ");
@@ -139,7 +130,6 @@
     return (value != null) && value.contains(callee);
   }
 
-  private List<Node> leaves = null;
   private Set<DexEncodedMethod> singleCallSite = Sets.newIdentityHashSet();
   private Set<DexEncodedMethod> doubleCallSite = Sets.newIdentityHashSet();
 
@@ -159,7 +149,6 @@
     graph.breakCycles();
     assert graph.breakCycles() == 0;  // This time the cycles should be gone.
     graph.fillCallSiteSets(appInfo);
-    graph.fillInitialLeaves();
     return graph;
   }
 
@@ -195,16 +184,6 @@
     }
   }
 
-  private void fillInitialLeaves() {
-    assert leaves == null;
-    leaves = new ArrayList<>();
-    for (Node node : nodes.values()) {
-      if (node.isLeaf()) {
-        leaves.add(node);
-      }
-    }
-  }
-
   private static boolean allMethodsExists(DexApplication application, CallGraph graph) {
     for (DexProgramClass clazz : application.classes()) {
       clazz.forEachMethod( method -> { assert graph.nodes.get(method) != null; });
@@ -213,28 +192,10 @@
   }
 
   /**
-   * Remove all leaves (nodes with an call (outgoing) degree of 0).
-   *
-   * @return List of {@link DexEncodedMethod} of the leaves removed.
-   */
-  private List<DexEncodedMethod> removeLeaves() {
-    List<DexEncodedMethod> result = new ArrayList<>();
-    List<Node> newLeaves = new ArrayList<>();
-    for (Node leaf : leaves) {
-      assert nodes.containsKey(leaf.method) && nodes.get(leaf.method).callees.isEmpty();
-      remove(leaf, newLeaves);
-      result.add(leaf.method);
-    }
-    leaves = newLeaves;
-    return result;
-  }
-
-  /**
-   * Pick the next set of leaves (nodes with an call (outgoing) degree of 0) if any.
+   * Extract the next set of leaves (nodes with an call (outgoing) degree of 0) if any.
    * <p>
-   * If the graph has no leaves then some cycles in the graph will be broken to create a set of
-   * leaves. See {@link #breakCycles} on how cycles are broken. This ensures that at least one
-   * leave is returned if the graph is not empty.
+   * All nodes in the graph are extracted if called repeatedly until null is returned.
+   * Please note that there are no cycles in this graph (see {@link #breakCycles}).
    * <p>
    *
    * @return  List of {@link DexEncodedMethod}.
@@ -243,13 +204,16 @@
     if (isEmpty()) {
       return null;
     }
-    List<DexEncodedMethod> leaves = removeLeaves();
-    assert leaves.size() > 0;
-    leaves.forEach( leaf -> { assert !leaf.isProcessed(); });
-    return leaves;
+    // First identify all leaves before removing them from the graph.
+    List<Node> leaves = nodes.values().stream().filter(Node::isLeaf).collect(Collectors.toList());
+    leaves.forEach( leaf -> {
+      leaf.callers.forEach( caller -> caller.callees.remove(leaf));
+      nodes.remove(leaf.method);
+    });
+    return leaves.stream().map( leaf -> leaf.method).collect(Collectors.toList());
   }
 
-  private int traverse(Node node, HashSet<Node> stack, HashSet<Node> marked) {
+  private int traverse(Node node, Set<Node> stack, Set<Node> marked) {
     int numberOfCycles = 0;
     if (!marked.contains(node)) {
       assert !stack.contains(node);
@@ -268,7 +232,8 @@
           // We have a cycle; break it by removing node->callee.
           toBeRemoved.add(callee);
           callee.callers.remove(node);
-          breakers.computeIfAbsent(node.method, ignore -> new HashSet<>()).add(callee.method);
+          breakers.computeIfAbsent(node.method,
+              ignore -> Sets.newIdentityHashSet()).add(callee.method);
         } else {
           numberOfCycles += traverse(callee, stack, marked);
         }
@@ -287,8 +252,8 @@
     // Break cycles in this call graph by removing edges causing cycles.
     // The remove edges are stored in @breakers.
     int numberOfCycles = 0;
-    HashSet<Node> stack = new HashSet<>();
-    HashSet<Node> marked = new HashSet<>();
+    Set<Node> stack = Sets.newIdentityHashSet();
+    Set<Node> marked = Sets.newIdentityHashSet();
     for(Node node : nodes.values()) {
       numberOfCycles += traverse(node, stack, marked);
     }
@@ -311,18 +276,6 @@
     callee.invokeCount++;
   }
 
-  private void remove(Node node, List<Node> leaves) {
-    assert node != null;
-    for (Node caller : node.callers) {
-      boolean removed = caller.callees.remove(node);
-      if (caller.isLeaf()) {
-        leaves.add(caller);
-      }
-      assert removed;
-    }
-    nodes.remove(node.method);
-  }
-
   public boolean isEmpty() {
     return nodes.size() == 0;
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index 3ab231c..4cd44ef 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -107,25 +107,19 @@
     keep.ensureValid(minificationEnabled);
     for (DexProgramClass clazz : appInfo.classes()) {
       clazz.annotations = stripAnnotations(clazz.annotations, this::filterAnnotations);
-      processMethods(clazz.virtualMethods());
-      processMethods(clazz.directMethods());
-      processFields(clazz.staticFields());
-      processFields(clazz.instanceFields());
+      clazz.forEachMethod(this::processMethod);
+      clazz.forEachField(this::processField);
     }
   }
 
-  private void processMethods(DexEncodedMethod[] methods) {
-    for (DexEncodedMethod method : methods) {
-      method.annotations = stripAnnotations(method.annotations, this::filterAnnotations);
-      method.parameterAnnotations = stripAnnotations(method.parameterAnnotations,
-          this::filterParameterAnnotations);
-    }
+  private void processMethod(DexEncodedMethod method) {
+    method.annotations = stripAnnotations(method.annotations, this::filterAnnotations);
+    method.parameterAnnotations = stripAnnotations(method.parameterAnnotations,
+        this::filterParameterAnnotations);
   }
 
-  private void processFields(DexEncodedField[] fields) {
-    for (DexEncodedField field : fields) {
+  private void processField(DexEncodedField field) {
       field.annotations = stripAnnotations(field.annotations, this::filterAnnotations);
-    }
   }
 
   private DexAnnotationSetRefList stripAnnotations(DexAnnotationSetRefList annotations,
diff --git a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
index 75b7495..a7a27fe 100644
--- a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
+++ b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
@@ -24,25 +24,19 @@
 
   public void run() {
     for (DexProgramClass clazz : application.classes()) {
-      if (checkDiscarded.contains(clazz)) {
-        report(clazz);
-      }
-      processSubItems(clazz.directMethods());
-      processSubItems(clazz.virtualMethods());
-      processSubItems(clazz.staticFields());
-      processSubItems(clazz.instanceFields());
+      checkItem(clazz);
+      clazz.forEachMethod(this::checkItem);
+      clazz.forEachField(this::checkItem);
     }
     if (fail) {
       throw new CompilationError("Discard checks failed.");
     }
   }
 
-  private void processSubItems(DexItem[] items) {
-    Arrays.stream(items).filter(checkDiscarded::contains).forEach(this::report);
-  }
-
-  private void report(DexItem item) {
-    System.err.println("Item " + item.toSourceString() + " was not discarded.");
-    fail = true;
+  private void checkItem(DexItem item) {
+    if (checkDiscarded.contains(item)) {
+      System.err.println("Item " + item.toSourceString() + " was not discarded.");
+      fail = true;
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
index 4b978e2..8a7ee43 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -150,20 +150,11 @@
       addMainDexType(type);
       // Super and interfaces are live, no need to add them.
       traceAnnotationsDirectDendencies(clazz.annotations);
-      for (DexEncodedField field : clazz.instanceFields()) {
-        addMainDexType(field.field.type);
-      }
-      for (DexEncodedField field : clazz.staticFields()) {
-        addMainDexType(field.field.type);
-      }
-      for (DexEncodedMethod method : clazz.directMethods()) {
+      clazz.forEachField( field -> addMainDexType(field.field.type));
+      clazz.forEachMethod( method -> {
         traceMethodDirectDependencies(method.method);
         method.registerReachableDefinitions(codeDirectReferenceCollector);
-      }
-      for (DexEncodedMethod method : clazz.virtualMethods()) {
-        traceMethodDirectDependencies(method.method);
-        method.registerReachableDefinitions(codeDirectReferenceCollector);
-      }
+      });
     }
   }