Introduce @NoParameterTypeStrengthening annotation for testing

Change-Id: I3cba1e2f9002544d06914b03dee3f537c87c45a1
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
index 9938bbc..9994ab1 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -24,8 +24,11 @@
     return bottom().joiner();
   }
 
+  private final boolean allowParameterTypeStrengthening;
+
   private KeepMethodInfo(Builder builder) {
     super(builder);
+    this.allowParameterTypeStrengthening = builder.isParameterTypeStrengtheningAllowed();
   }
 
   // This builder is not private as there are known instances where it is safe to modify keep info
@@ -39,6 +42,16 @@
     return isParameterRemovalAllowed(configuration);
   }
 
+  public boolean isParameterTypeStrengtheningAllowed(GlobalKeepInfoConfiguration configuration) {
+    return isOptimizationAllowed(configuration)
+        && isShrinkingAllowed(configuration)
+        && internalIsParameterTypeStrengtheningAllowed();
+  }
+
+  boolean internalIsParameterTypeStrengtheningAllowed() {
+    return allowParameterTypeStrengthening;
+  }
+
   public Joiner joiner() {
     assert !isTop();
     return new Joiner(this);
@@ -60,12 +73,32 @@
 
   public static class Builder extends KeepInfo.Builder<Builder, KeepMethodInfo> {
 
+    private boolean allowParameterTypeStrengthening;
+
     private Builder() {
       super();
     }
 
     private Builder(KeepMethodInfo original) {
       super(original);
+      allowParameterTypeStrengthening = original.internalIsParameterTypeStrengtheningAllowed();
+    }
+
+    public boolean isParameterTypeStrengtheningAllowed() {
+      return allowParameterTypeStrengthening;
+    }
+
+    public Builder setAllowParameterTypeStrengthening(boolean allowParameterTypeStrengthening) {
+      this.allowParameterTypeStrengthening = allowParameterTypeStrengthening;
+      return self();
+    }
+
+    public Builder allowParameterTypeStrengthening() {
+      return setAllowParameterTypeStrengthening(true);
+    }
+
+    public Builder disallowParameterTypeStrengthening() {
+      return setAllowParameterTypeStrengthening(false);
     }
 
     @Override
@@ -89,9 +122,26 @@
     }
 
     @Override
+    boolean internalIsEqualTo(KeepMethodInfo other) {
+      return super.internalIsEqualTo(other)
+          && isParameterTypeStrengtheningAllowed()
+              == other.internalIsParameterTypeStrengtheningAllowed();
+    }
+
+    @Override
     public KeepMethodInfo doBuild() {
       return new KeepMethodInfo(this);
     }
+
+    @Override
+    public Builder makeTop() {
+      return super.makeTop().disallowParameterTypeStrengthening();
+    }
+
+    @Override
+    public Builder makeBottom() {
+      return super.makeBottom().allowParameterTypeStrengthening();
+    }
   }
 
   public static class Joiner extends KeepInfo.Joiner<Joiner, Builder, KeepMethodInfo> {
@@ -100,6 +150,11 @@
       super(info.builder());
     }
 
+    public Joiner disallowParameterTypeStrengthening() {
+      builder.disallowParameterTypeStrengthening();
+      return self();
+    }
+
     @Override
     public Joiner asMethodJoiner() {
       return this;
@@ -108,7 +163,10 @@
     @Override
     public Joiner merge(Joiner joiner) {
       // Should be extended to merge the fields of this class in case any are added.
-      return super.merge(joiner);
+      return super.merge(joiner)
+          .applyIf(
+              !joiner.builder.isParameterTypeStrengtheningAllowed(),
+              Joiner::disallowParameterTypeStrengthening);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/NoParameterTypeStrengtheningRule.java b/src/main/java/com/android/tools/r8/shaking/NoParameterTypeStrengtheningRule.java
new file mode 100644
index 0000000..94cec37
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/NoParameterTypeStrengtheningRule.java
@@ -0,0 +1,84 @@
+// Copyright (c) 2022, 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 NoParameterTypeStrengtheningRule extends ProguardConfigurationRule {
+
+  public static final String RULE_NAME = "noparametertypestrengthening";
+
+  public static class Builder
+      extends ProguardConfigurationRule.Builder<NoParameterTypeStrengtheningRule, Builder> {
+
+    private Builder() {
+      super();
+    }
+
+    @Override
+    public NoParameterTypeStrengtheningRule.Builder self() {
+      return this;
+    }
+
+    @Override
+    public NoParameterTypeStrengtheningRule build() {
+      return new NoParameterTypeStrengtheningRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules);
+    }
+  }
+
+  private NoParameterTypeStrengtheningRule(
+      Origin origin,
+      Position position,
+      String source,
+      List<ProguardTypeMatcher> classAnnotations,
+      ProguardAccessFlags classAccessFlags,
+      ProguardAccessFlags negatedClassAccessFlags,
+      boolean classTypeNegated,
+      ProguardClassType classType,
+      ProguardClassNameList classNames,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
+      ProguardTypeMatcher inheritanceClassName,
+      boolean inheritanceIsExtends,
+      List<ProguardMemberRule> memberRules) {
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  String typeString() {
+    return RULE_NAME;
+  }
+}
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 b92040b..13cabf2 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -500,6 +500,11 @@
           configurationBuilder.addRule(rule);
           return true;
         }
+        if (acceptString(NoParameterTypeStrengtheningRule.RULE_NAME)) {
+          ProguardConfigurationRule rule = parseNoParameterTypeStrengtheningRule(optionStart);
+          configurationBuilder.addRule(rule);
+          return true;
+        }
         if (acceptString("neverpropagatevalue")) {
           MemberValuePropagationRule rule =
               parseMemberValuePropagationRule(MemberValuePropagationRule.Type.NEVER, optionStart);
@@ -828,6 +833,17 @@
       return keepRuleBuilder.build();
     }
 
+    private NoParameterTypeStrengtheningRule parseNoParameterTypeStrengtheningRule(Position start)
+        throws ProguardRuleParserException {
+      NoParameterTypeStrengtheningRule.Builder keepRuleBuilder =
+          NoParameterTypeStrengtheningRule.builder().setOrigin(origin).setStart(start);
+      parseClassSpec(keepRuleBuilder, false);
+      Position end = getPosition();
+      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
+      keepRuleBuilder.setEnd(end);
+      return keepRuleBuilder.build();
+    }
+
     private MemberValuePropagationRule parseMemberValuePropagationRule(
         MemberValuePropagationRule.Type type, Position start)
         throws ProguardRuleParserException {
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 3644e3d..80756a1 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -267,6 +267,7 @@
         markMatchingFields(clazz, memberKeepRules, rule, null, ifRule);
       } else if (rule instanceof InlineRule
           || rule instanceof ConstantArgumentRule
+          || rule instanceof NoParameterTypeStrengtheningRule
           || rule instanceof UnusedArgumentRule
           || rule instanceof ReprocessMethodRule
           || rule instanceof WhyAreYouNotInliningRule) {
@@ -1243,6 +1244,13 @@
       } else if (context instanceof NoHorizontalClassMergingRule) {
         noHorizontalClassMerging.add(item.asClass().type);
         context.markAsUsed();
+      } else if (context instanceof NoParameterTypeStrengtheningRule) {
+        assert item.isProgramMethod();
+        dependentMinimumKeepInfo
+            .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference())
+            .asMethodJoiner()
+            .disallowParameterTypeStrengthening();
+        context.markAsUsed();
       } else if (context instanceof MemberValuePropagationRule) {
         switch (((MemberValuePropagationRule) context).getType()) {
           case NEVER:
diff --git a/src/test/java/com/android/tools/r8/NoParameterTypeStrengthening.java b/src/test/java/com/android/tools/r8/NoParameterTypeStrengthening.java
new file mode 100644
index 0000000..c862859
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/NoParameterTypeStrengthening.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.PARAMETER})
+public @interface NoParameterTypeStrengthening {}
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 1fa7630..1a4706e 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.shaking.CollectingGraphConsumer;
 import com.android.tools.r8.shaking.NoFieldTypeStrengtheningRule;
 import com.android.tools.r8.shaking.NoHorizontalClassMergingRule;
+import com.android.tools.r8.shaking.NoParameterTypeStrengtheningRule;
 import com.android.tools.r8.shaking.NoUnusedInterfaceRemovalRule;
 import com.android.tools.r8.shaking.NoVerticalClassMergingRule;
 import com.android.tools.r8.shaking.ProguardConfiguration;
@@ -436,6 +437,11 @@
         "-" + name + " class * { @" + annotation.getTypeName() + " <fields>; }");
   }
 
+  T addInternalMatchAnnotationOnMethodRule(String name, Class<? extends Annotation> annotation) {
+    return addInternalKeepRules(
+        "-" + name + " class * { @" + annotation.getTypeName() + " <methods>; }");
+  }
+
   T addInternalMatchInterfaceRule(String name, Class<?> matchInterface) {
     return addInternalKeepRules("-" + name + " @" + matchInterface.getTypeName() + " class *");
   }
@@ -502,6 +508,12 @@
             NoFieldTypeStrengtheningRule.RULE_NAME, NoFieldTypeStrengthening.class);
   }
 
+  public T enableNoParameterTypeStrengtheningAnnotations() {
+    return addNoParameterTypeStrengtheningAnnotation()
+        .addInternalMatchAnnotationOnMethodRule(
+            NoParameterTypeStrengtheningRule.RULE_NAME, NoParameterTypeStrengthening.class);
+  }
+
   public T enableNoUnusedInterfaceRemovalAnnotations() {
     return addNoUnusedInterfaceRemovalAnnotations()
         .addInternalMatchInterfaceRule(
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 7fc1ecc..9ed8247 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -466,6 +466,10 @@
     return addTestingAnnotation(NoHorizontalClassMerging.class);
   }
 
+  public final T addNoParameterTypeStrengtheningAnnotation() {
+    return addTestingAnnotation(NoParameterTypeStrengthening.class);
+  }
+
   public final T addNoUnusedInterfaceRemovalAnnotations() {
     return addTestingAnnotation(NoUnusedInterfaceRemoval.class);
   }