Add ResourceShrinker method and class visitors

Extends the ResourceShrinker ResourceChecker interface to include
methods for checking if methods and classes are currently being visited.
This will be used for checking if methods in R classes are being visited
in Android Gradle Plugin.

Bug: 170709331
Test: ResourceShrinkerTest
Change-Id: Ide0b1aa2f6cf6cd56470ac3623119ae2bce74fec
diff --git a/src/main/java/com/android/tools/r8/ResourceShrinker.java b/src/main/java/com/android/tools/r8/ResourceShrinker.java
index 77abde6..9a03299 100644
--- a/src/main/java/com/android/tools/r8/ResourceShrinker.java
+++ b/src/main/java/com/android/tools/r8/ResourceShrinker.java
@@ -140,6 +140,14 @@
     void referencedStaticField(String internalName, String fieldName);
 
     void referencedMethod(String internalName, String methodName, String methodDescriptor);
+
+    default void startMethodVisit() {}
+
+    default void endMethodVisit() {}
+
+    default void startClassVisit() {}
+
+    default void endClassVisit() {}
   }
 
   private static final class DexClassUsageVisitor {
@@ -153,6 +161,7 @@
     }
 
     public void visit() {
+      callback.startClassVisit();
       if (!callback.shouldProcess(classDef.type.getInternalName())) {
         return;
       }
@@ -165,12 +174,15 @@
       }
 
       for (DexEncodedMethod method : classDef.allMethodsSorted()) {
+        callback.startMethodVisit();
         processMethod(method);
+        callback.endMethodVisit();
       }
 
       if (classDef.hasClassOrMemberAnnotations()) {
         processAnnotations(classDef);
       }
+      callback.endClassVisit();
     }
 
     private void processFieldValue(DexValue value) {
diff --git a/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java b/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java
index 2a0826a..360881c 100644
--- a/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java
+++ b/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java
@@ -38,6 +38,8 @@
     Set<String> strings = Sets.newHashSet();
     List<List<String>> fields = Lists.newArrayList();
     List<List<String>> methods = Lists.newArrayList();
+    int methodsVisited = 0;
+    int classesVisited = 0;
 
     @Override
     public boolean shouldProcess(String internalName) {
@@ -67,6 +69,22 @@
       }
       methods.add(Lists.newArrayList(internalName, methodName, methodDescriptor));
     }
+
+    @Override
+    public void startMethodVisit() {
+      methodsVisited++;
+    }
+
+    @Override
+    public void endMethodVisit() {}
+
+    @Override
+    public void startClassVisit() {
+      classesVisited++;
+    }
+
+    @Override
+    public void endClassVisit() {}
   }
 
   private static class EmptyClass {
@@ -133,6 +151,24 @@
     assertThat(analysis.methods, is(Lists.newArrayList()));
   }
 
+  @SuppressWarnings("unused")
+  private static class ClassesAndMethodsVisited {
+    final int value = getValue();
+
+    int getValue() {
+      return true ? 0 : 1;
+    }
+  }
+
+  @Test
+  public void testNumberOfMethodsAndClassesVisited()
+      throws CompilationFailedException, IOException, ExecutionException {
+    TrackAll analysis = runAnalysis(ClassesAndMethodsVisited.class);
+
+    assertThat(analysis.methodsVisited, is(2));
+    assertThat(analysis.classesVisited, is(1));
+  }
+
   @Retention(RetentionPolicy.RUNTIME)
   private @interface IntAnnotation {
     int value() default 10;