Add keep info value for retaining method parameter names

Fixes: b/343907109
Change-Id: I881c54f1f8b2629577bc167a5a7955c147f318bb
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 f58aab9..bcfa888 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -114,10 +114,9 @@
           // TODO(b/343909250): Is this supposed to be kept on all live items?
           return config.sourceDebugExtension;
         }
-        if (config.methodParameters
-            && DexAnnotation.isParameterNameAnnotation(annotation, dexItemFactory)) {
-          // TODO(b/343907109): This should be conditional on its own keep info bit.
-          return true;
+        if (DexAnnotation.isParameterNameAnnotation(annotation, dexItemFactory)) {
+          KeepMethodInfo methodInfo = keepInfo.asMethodInfo();
+          return methodInfo != null && !methodInfo.isParameterNamesRemovalAllowed(options);
         }
         if (isAnnotationOnAnnotationClass
             && DexAnnotation.isAnnotationDefaultAnnotation(annotation, dexItemFactory)
diff --git a/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java b/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
index c924664..7dfbfeb 100644
--- a/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
@@ -24,6 +24,8 @@
 
   boolean isForceKeepExceptionsAttributeEnabled();
 
+  boolean isForceKeepMethodParametersAttributeEnabled();
+
   boolean isKeepEnclosingMethodAttributeEnabled();
 
   boolean isKeepInnerClassesAttributeEnabled();
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 ae8ae32..571d3e8 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -42,6 +42,7 @@
   private final boolean allowSingleCallerInlining;
   private final boolean allowUnusedArgumentOptimization;
   private final boolean allowUnusedReturnValueOptimization;
+  private final boolean allowParameterNamesRemoval;
   private final KeepAnnotationCollectionInfo parameterAnnotationsInfo;
 
   protected KeepMethodInfo(Builder builder) {
@@ -60,6 +61,7 @@
     this.allowSingleCallerInlining = builder.isSingleCallerInliningAllowed();
     this.allowUnusedArgumentOptimization = builder.isUnusedArgumentOptimizationAllowed();
     this.allowUnusedReturnValueOptimization = builder.isUnusedReturnValueOptimizationAllowed();
+    this.allowParameterNamesRemoval = builder.isParameterNamesRemovalAllowed();
     this.parameterAnnotationsInfo = builder.getParameterAnnotationsInfo().build();
   }
 
@@ -242,6 +244,15 @@
     return allowUnusedReturnValueOptimization;
   }
 
+  public boolean isParameterNamesRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
+    return !configuration.isForceKeepMethodParametersAttributeEnabled()
+        && internalIsParameterNamesRemovalAllowed();
+  }
+
+  boolean internalIsParameterNamesRemovalAllowed() {
+    return allowParameterNamesRemoval;
+  }
+
   public Joiner joiner() {
     assert !isTop();
     return new Joiner(this);
@@ -273,6 +284,7 @@
     private boolean allowSingleCallerInlining;
     private boolean allowUnusedArgumentOptimization;
     private boolean allowUnusedReturnValueOptimization;
+    private boolean allowParameterNamesRemoval;
     private KeepAnnotationCollectionInfo.Builder parameterAnnotationsInfo;
 
     public Builder() {
@@ -296,6 +308,7 @@
       allowUnusedArgumentOptimization = original.internalIsUnusedArgumentOptimizationAllowed();
       allowUnusedReturnValueOptimization =
           original.internalIsUnusedReturnValueOptimizationAllowed();
+      allowParameterNamesRemoval = original.internalIsParameterNamesRemovalAllowed();
       parameterAnnotationsInfo = original.internalParameterAnnotationsInfo().toBuilder();
     }
 
@@ -426,7 +439,16 @@
       return self();
     }
 
-    KeepAnnotationCollectionInfo.Builder getParameterAnnotationsInfo() {
+    public boolean isParameterNamesRemovalAllowed() {
+      return allowParameterNamesRemoval;
+    }
+
+    public Builder setAllowParameterNamesRemoval(boolean allowParameterNamesRemoval) {
+      this.allowParameterNamesRemoval = allowParameterNamesRemoval;
+      return self();
+    }
+
+    public KeepAnnotationCollectionInfo.Builder getParameterAnnotationsInfo() {
       return parameterAnnotationsInfo;
     }
 
@@ -476,6 +498,7 @@
               == other.internalIsUnusedArgumentOptimizationAllowed()
           && isUnusedReturnValueOptimizationAllowed()
               == other.internalIsUnusedReturnValueOptimizationAllowed()
+          && isParameterNamesRemovalAllowed() == other.internalIsParameterNamesRemovalAllowed()
           && parameterAnnotationsInfo.isEqualTo(other.parameterAnnotationsInfo);
     }
 
@@ -501,6 +524,7 @@
           .setAllowSingleCallerInlining(false)
           .setAllowUnusedArgumentOptimization(false)
           .setAllowUnusedReturnValueOptimization(false)
+          .setAllowParameterNamesRemoval(false)
           .setParameterAnnotationInfo(KeepAnnotationCollectionInfo.Builder.createTop());
     }
 
@@ -521,6 +545,7 @@
           .setAllowSingleCallerInlining(true)
           .setAllowUnusedArgumentOptimization(true)
           .setAllowUnusedReturnValueOptimization(true)
+          .setAllowParameterNamesRemoval(true)
           .setParameterAnnotationInfo(KeepAnnotationCollectionInfo.Builder.createBottom());
     }
   }
@@ -605,6 +630,11 @@
       return self();
     }
 
+    public Joiner disallowParameterNamesRemoval() {
+      builder.setAllowParameterNamesRemoval(false);
+      return self();
+    }
+
     public Joiner disallowParameterAnnotationsRemoval() {
       builder.setParameterAnnotationInfo(KeepAnnotationCollectionInfo.Builder.createTop());
       return self();
@@ -654,7 +684,10 @@
               Joiner::disallowUnusedArgumentOptimization)
           .applyIf(
               !joiner.builder.isUnusedReturnValueOptimizationAllowed(),
-              Joiner::disallowUnusedReturnValueOptimization);
+              Joiner::disallowUnusedReturnValueOptimization)
+          .applyIf(
+              !joiner.builder.isParameterNamesRemovalAllowed(),
+              Joiner::disallowParameterNamesRemoval);
     }
 
     @Override
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 f6ff126..3d5324b 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -1678,6 +1678,11 @@
         context.markAsUsed();
       }
 
+      if (attributesConfig.methodParameters && item.isMethod()) {
+        itemJoiner.computeIfAbsent().asMethodJoiner().disallowParameterNamesRemoval();
+        context.markAsUsed();
+      }
+
       if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) {
         itemJoiner.computeIfAbsent().disallowMinification();
         context.markAsUsed();
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 28bc741..91fbada 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -828,6 +828,13 @@
   }
 
   @Override
+  public boolean isForceKeepMethodParametersAttributeEnabled() {
+    return proguardConfiguration == null
+        || (isForceProguardCompatibilityEnabled()
+            && proguardConfiguration.getKeepAttributes().methodParameters);
+  }
+
+  @Override
   public boolean isKeepEnclosingMethodAttributeEnabled() {
     return proguardConfiguration.getKeepAttributes().enclosingMethod;
   }