Add a Proguard testing directive -whyareyounotinlining

This CL merely parses -whyareyounotinlining as a testing option in the Proguard configuration parser. It is a no-op to use the directive.

Change-Id: I0662fbbe4c1ea68cd6aef32cf7b6f317e018a593
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index de9aab7..4762db0 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -143,6 +143,8 @@
   public final Set<DexMethod> forceInline;
   /** All methods that *must* never be inlined due to a configuration directive (testing only). */
   public final Set<DexMethod> neverInline;
+  /** Items for which to print inlining decisions for (testing only). */
+  public final Set<DexMethod> whyAreYouNotInlining;
   /** All methods that may not have any parameters with a constant value removed. */
   public final Set<DexMethod> keepConstantArguments;
   /** All methods that may not have any unused arguments removed. */
@@ -211,6 +213,7 @@
       Set<DexMethod> alwaysInline,
       Set<DexMethod> forceInline,
       Set<DexMethod> neverInline,
+      Set<DexMethod> whyAreYouNotInlining,
       Set<DexMethod> keepConstantArguments,
       Set<DexMethod> keepUnusedArguments,
       Set<DexType> neverClassInline,
@@ -250,6 +253,7 @@
     this.alwaysInline = alwaysInline;
     this.forceInline = forceInline;
     this.neverInline = neverInline;
+    this.whyAreYouNotInlining = whyAreYouNotInlining;
     this.keepConstantArguments = keepConstantArguments;
     this.keepUnusedArguments = keepUnusedArguments;
     this.neverClassInline = neverClassInline;
@@ -290,6 +294,7 @@
       Set<DexMethod> alwaysInline,
       Set<DexMethod> forceInline,
       Set<DexMethod> neverInline,
+      Set<DexMethod> whyAreYouNotInlining,
       Set<DexMethod> keepConstantArguments,
       Set<DexMethod> keepUnusedArguments,
       Set<DexType> neverClassInline,
@@ -329,6 +334,7 @@
     this.alwaysInline = alwaysInline;
     this.forceInline = forceInline;
     this.neverInline = neverInline;
+    this.whyAreYouNotInlining = whyAreYouNotInlining;
     this.keepConstantArguments = keepConstantArguments;
     this.keepUnusedArguments = keepUnusedArguments;
     this.neverClassInline = neverClassInline;
@@ -380,6 +386,7 @@
         previous.alwaysInline,
         previous.forceInline,
         previous.neverInline,
+        previous.whyAreYouNotInlining,
         previous.keepConstantArguments,
         previous.keepUnusedArguments,
         previous.neverClassInline,
@@ -454,6 +461,8 @@
     this.alwaysInline = lense.rewriteMethodsWithRenamedSignature(previous.alwaysInline);
     this.forceInline = lense.rewriteMethodsWithRenamedSignature(previous.forceInline);
     this.neverInline = lense.rewriteMethodsWithRenamedSignature(previous.neverInline);
+    this.whyAreYouNotInlining =
+        lense.rewriteMethodsWithRenamedSignature(previous.whyAreYouNotInlining);
     this.keepConstantArguments =
         lense.rewriteMethodsWithRenamedSignature(previous.keepConstantArguments);
     this.keepUnusedArguments =
@@ -512,6 +521,7 @@
     this.alwaysInline = previous.alwaysInline;
     this.forceInline = previous.forceInline;
     this.neverInline = previous.neverInline;
+    this.whyAreYouNotInlining = previous.whyAreYouNotInlining;
     this.keepConstantArguments = previous.keepConstantArguments;
     this.keepUnusedArguments = previous.keepUnusedArguments;
     this.neverClassInline = previous.neverClassInline;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 80aa238..57ed2d3 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2211,6 +2211,7 @@
             rootSet.alwaysInline,
             rootSet.forceInline,
             rootSet.neverInline,
+            rootSet.whyAreYouNotInlining,
             rootSet.keepConstantArguments,
             rootSet.keepUnusedArguments,
             rootSet.neverClassInline,
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index ec4beec..0f62be2 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -451,6 +451,11 @@
           configurationBuilder.addRule(rule);
           return true;
         }
+        if (acceptString("whyareyounotinlining")) {
+          WhyAreYouNotInliningRule rule = parseWhyAreYouNotInliningRule(optionStart);
+          configurationBuilder.addRule(rule);
+          return true;
+        }
       }
       return false;
     }
@@ -771,6 +776,17 @@
       return keepRuleBuilder.build();
     }
 
+    private WhyAreYouNotInliningRule parseWhyAreYouNotInliningRule(Position start)
+        throws ProguardRuleParserException {
+      WhyAreYouNotInliningRule.Builder keepRuleBuilder =
+          WhyAreYouNotInliningRule.builder().setOrigin(origin).setStart(start);
+      parseClassSpec(keepRuleBuilder, false);
+      Position end = getPosition();
+      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
+      keepRuleBuilder.setEnd(end);
+      return keepRuleBuilder.build();
+    }
+
     void verifyAndLinkBackReferences(Iterable<ProguardWildcard> wildcards) {
       List<Pattern> patterns = new ArrayList<>();
       boolean backReferenceStarted = false;
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 62b2fd9..f862bb4 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -72,6 +72,7 @@
   private final Set<DexMethod> alwaysInline = Sets.newIdentityHashSet();
   private final Set<DexMethod> forceInline = Sets.newIdentityHashSet();
   private final Set<DexMethod> neverInline = Sets.newIdentityHashSet();
+  private final Set<DexMethod> whyAreYouNotInlining = Sets.newIdentityHashSet();
   private final Set<DexMethod> keepParametersWithConstantValue = Sets.newIdentityHashSet();
   private final Set<DexMethod> keepUnusedArguments = Sets.newIdentityHashSet();
   private final Set<DexType> neverClassInline = Sets.newIdentityHashSet();
@@ -203,7 +204,8 @@
         }
       } else if (rule instanceof InlineRule
           || rule instanceof ConstantArgumentRule
-          || rule instanceof UnusedArgumentRule) {
+          || rule instanceof UnusedArgumentRule
+          || rule instanceof WhyAreYouNotInliningRule) {
         markMatchingMethods(clazz, memberKeepRules, rule, null, ifRule);
       } else if (rule instanceof ClassInlineRule) {
         if (allRulesSatisfied(memberKeepRules, clazz)) {
@@ -286,6 +288,7 @@
         alwaysInline,
         forceInline,
         neverInline,
+        whyAreYouNotInlining,
         keepParametersWithConstantValue,
         keepUnusedArguments,
         neverClassInline,
@@ -948,6 +951,12 @@
         }
         context.markAsUsed();
       }
+    } else if (context instanceof WhyAreYouNotInliningRule) {
+      if (!item.isDexEncodedMethod()) {
+        throw new Unreachable();
+      }
+      whyAreYouNotInlining.add(item.asDexEncodedMethod().method);
+      context.markAsUsed();
     } else if (context instanceof ClassInlineRule) {
       switch (((ClassInlineRule) context).getType()) {
         case NEVER:
@@ -1025,6 +1034,7 @@
     public final Set<DexMethod> alwaysInline;
     public final Set<DexMethod> forceInline;
     public final Set<DexMethod> neverInline;
+    public final Set<DexMethod> whyAreYouNotInlining;
     public final Set<DexMethod> keepConstantArguments;
     public final Set<DexMethod> keepUnusedArguments;
     public final Set<DexType> neverClassInline;
@@ -1048,6 +1058,7 @@
         Set<DexMethod> alwaysInline,
         Set<DexMethod> forceInline,
         Set<DexMethod> neverInline,
+        Set<DexMethod> whyAreYouNotInlining,
         Set<DexMethod> keepConstantArguments,
         Set<DexMethod> keepUnusedArguments,
         Set<DexType> neverClassInline,
@@ -1068,6 +1079,7 @@
       this.alwaysInline = Collections.unmodifiableSet(alwaysInline);
       this.forceInline = Collections.unmodifiableSet(forceInline);
       this.neverInline = neverInline;
+      this.whyAreYouNotInlining = whyAreYouNotInlining;
       this.keepConstantArguments = keepConstantArguments;
       this.keepUnusedArguments = keepUnusedArguments;
       this.neverClassInline = neverClassInline;
diff --git a/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java b/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
new file mode 100644
index 0000000..aa52ca3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2019, 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.shaking;
+
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+import java.util.List;
+
+public class WhyAreYouNotInliningRule extends ProguardConfigurationRule {
+
+  public static class Builder
+      extends ProguardConfigurationRule.Builder<WhyAreYouNotInliningRule, Builder> {
+
+    private Builder() {
+      super();
+    }
+
+    @Override
+    public Builder self() {
+      return this;
+    }
+
+    @Override
+    public WhyAreYouNotInliningRule build() {
+      return new WhyAreYouNotInliningRule(
+          origin,
+          getPosition(),
+          source,
+          classAnnotation,
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          inheritanceAnnotation,
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules);
+    }
+  }
+
+  private WhyAreYouNotInliningRule(
+      Origin origin,
+      Position position,
+      String source,
+      ProguardTypeMatcher classAnnotation,
+      ProguardAccessFlags classAccessFlags,
+      ProguardAccessFlags negatedClassAccessFlags,
+      boolean classTypeNegated,
+      ProguardClassType classType,
+      ProguardClassNameList classNames,
+      ProguardTypeMatcher inheritanceAnnotation,
+      ProguardTypeMatcher inheritanceClassName,
+      boolean inheritanceIsExtends,
+      List<ProguardMemberRule> memberRules) {
+    super(
+        origin,
+        position,
+        source,
+        classAnnotation,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotation,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  String typeString() {
+    return "whyareyounotinlining";
+  }
+}