Merge "Enable logging of field minification states"
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
index 8c24e8b..c93efad 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -14,7 +14,9 @@
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Sets;
+import java.io.PrintStream;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Function;
 
 class FieldNameMinifier extends MemberNameMinifier<DexField, DexType> {
@@ -128,7 +130,6 @@
       return;
     }
     assert clazz.isInterface();
-
     NamingState<DexType, ?> state = minifierState.getState(clazz.type);
     assert state != null;
     for (DexEncodedField field : clazz.fields()) {
@@ -138,6 +139,14 @@
 
   private void renameField(DexEncodedField encodedField, NamingState<DexType, ?> state) {
     DexField field = encodedField.field;
+
+    Set<String> loggingFilter = options.extensiveFieldMinifierLoggingFilter;
+    if (!loggingFilter.isEmpty()) {
+      if (loggingFilter.contains(field.toSourceString())) {
+        print(field, state, System.out);
+      }
+    }
+
     if (!state.isReserved(field.name, field.type)) {
       renaming.put(
           field, state.assignNewNameFor(field, field.name, field.type, useUniqueMemberNames));
@@ -182,4 +191,12 @@
       renaming.put(field, renaming.get(definition.field));
     }
   }
+
+  private void print(DexField field, NamingState<DexType, ?> state, PrintStream out) {
+    out.println("--------------------------------------------------------------------------------");
+    out.println("FieldNameMinifier(`" + field.toSourceString() + "`)");
+    out.println("--------------------------------------------------------------------------------");
+    state.printState(field.type, minifierState::getStateKey, "", out);
+    out.println();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index e9932e1..524c17d 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -327,7 +327,7 @@
       out.print(".");
       out.print(name.toSourceString());
       out.println(proto.toSmaliString());
-      parent.printState(proto, indentation + "  ", out);
+      parent.printState(proto, stateKeyGetter, indentation + "  ", out);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 0b7bf45..9862f04 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -136,7 +136,7 @@
 
   static class MinifierMemberNamingStrategy implements MemberNamingStrategy {
 
-    char[] EMPTY_CHAR_ARRAY = new char[0];
+    public static char[] EMPTY_CHAR_ARRAY = new char[0];
 
     private final DexItemFactory factory;
 
diff --git a/src/main/java/com/android/tools/r8/naming/NamingState.java b/src/main/java/com/android/tools/r8/naming/NamingState.java
index c44c70d..502fae2 100644
--- a/src/main/java/com/android/tools/r8/naming/NamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/NamingState.java
@@ -3,11 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import static com.android.tools.r8.naming.Minifier.MinifierMemberNamingStrategy.EMPTY_CHAR_ARRAY;
+
 import com.android.tools.r8.graph.CachedHashValueDexItem;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.naming.MemberNameMinifier.MemberNamingStrategy;
+import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.HashBasedTable;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -73,12 +77,8 @@
     // TODO(herhut): Maybe allocate these sparsely and search via state chain.
     InternalState result = usedNames.get(key);
     if (result == null) {
-      if (parent != null) {
-        InternalState parentState = parent.getOrCreateInternalStateFor(key);
-        result = parentState.createChild();
-      } else {
-        result = new InternalState(itemFactory, null, dictionary);
-      }
+      InternalState parentState = parent != null ? parent.getOrCreateInternalStateFor(key) : null;
+      result = new InternalState(itemFactory, parentState, dictionary);
       usedNames.put(key, result);
     }
     return result;
@@ -139,12 +139,23 @@
     state.addRenaming(original, key, newName);
   }
 
-  void printState(ProtoType proto, String indentation, PrintStream out) {
+  void printState(
+      ProtoType proto,
+      Function<NamingState<ProtoType, ?>, DexType> stateKeyGetter,
+      String indentation,
+      PrintStream out) {
     KeyType key = keyTransform.apply(proto);
-    InternalState state = findInternalStateFor(key);
+    InternalState state = getOrCreateInternalStateFor(key);
+    out.print(indentation);
+    out.print("NamingState(node=`");
+    out.print(stateKeyGetter.apply(this).toSourceString());
+    out.print("`, proto=`");
+    out.print(proto.toSourceString());
+    out.print("`, key=`");
+    out.print(key.toString());
+    out.println("`)");
     if (state != null) {
-      state.printReservedNames(indentation, out);
-      state.printRenamings(indentation, out);
+      state.printInternalState(this, stateKeyGetter, indentation + "  ", out);
     } else {
       out.print(indentation);
       out.println("<NO STATE>");
@@ -189,10 +200,6 @@
           && (parentInternalState == null || parentInternalState.isAvailable(name));
     }
 
-    InternalState createChild() {
-      return new InternalState(itemFactory, this, dictionaryIterator);
-    }
-
     void reserveName(DexString name) {
       if (reservedNames == null) {
         reservedNames = Sets.newIdentityHashSet();
@@ -256,6 +263,43 @@
       }
     }
 
+    void printInternalState(
+        NamingState<ProtoType, ?> expectedNamingState,
+        Function<NamingState<ProtoType, ?>, DexType> stateKeyGetter,
+        String indentation,
+        PrintStream out) {
+      assert expectedNamingState == NamingState.this;
+
+      DexType stateKey = stateKeyGetter.apply(expectedNamingState);
+      out.print(indentation);
+      out.print("InternalState(node=`");
+      out.print(stateKey != null ? stateKey.toSourceString() : "<GLOBAL>");
+      out.println("`)");
+
+      printLastName(indentation + "  ", out);
+      printReservedNames(indentation + "  ", out);
+      printRenamings(indentation + "  ", out);
+
+      if (parentInternalState != null) {
+        parentInternalState.printInternalState(
+            expectedNamingState.parent, stateKeyGetter, indentation + "  ", out);
+      }
+    }
+
+    void printLastName(String indentation, PrintStream out) {
+      out.print(indentation);
+      out.print("Last name: ");
+      if (nameCount > 1) {
+        out.print(StringUtils.numberToIdentifier(EMPTY_CHAR_ARRAY, nameCount - 1, false));
+        out.print(" (name count: ");
+        out.print(nameCount);
+        out.print(")");
+      } else {
+        out.print("<NONE>");
+      }
+      out.println();
+    }
+
     void printReservedNames(String indentation, PrintStream out) {
       out.print(indentation);
       out.print("Reserved names:");
@@ -270,9 +314,6 @@
         }
       }
       out.println();
-      if (parentInternalState != null) {
-        parentInternalState.printReservedNames(indentation + "  ", out);
-      }
     }
 
     void printRenamings(String indentation, PrintStream out) {
@@ -295,9 +336,6 @@
         }
       }
       out.println();
-      if (parentInternalState != null) {
-        parentInternalState.printRenamings(indentation + "  ", out);
-      }
     }
   }
 }
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 e595762..29a6036 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -227,6 +227,7 @@
   }
 
   public Set<String> extensiveLoggingFilter = getExtensiveLoggingFilter();
+  public Set<String> extensiveFieldMinifierLoggingFilter = getExtensiveFieldMinifierLoggingFilter();
   public Set<String> extensiveInterfaceMethodMinifierLoggingFilter =
       getExtensiveInterfaceMethodMinifierLoggingFilter();
 
@@ -304,6 +305,19 @@
     return ImmutableSet.of();
   }
 
+  private static Set<String> getExtensiveFieldMinifierLoggingFilter() {
+    String property =
+        System.getProperty("com.android.tools.r8.extensiveFieldMinifierLoggingFilter");
+    if (property != null) {
+      ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+      for (String method : property.split(";")) {
+        builder.add(method);
+      }
+      return builder.build();
+    }
+    return ImmutableSet.of();
+  }
+
   private static Set<String> getExtensiveInterfaceMethodMinifierLoggingFilter() {
     String property =
         System.getProperty("com.android.tools.r8.extensiveInterfaceMethodMinifierLoggingFilter");