Add a @NoAccessModification annotation for testing

Change-Id: I8e3df1bedd3819e56abdb317385ec29c34d9ef40
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java
index f234a09..bc7d2ea 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java
@@ -7,12 +7,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class KeepConstantArgumentRule extends NoOptimizationBaseRule<KeepConstantArgumentRule> {
+public class KeepConstantArgumentRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "keepconstantarguments";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<KeepConstantArgumentRule, Builder> {
+      extends ProguardConfigurationRule.Builder<KeepConstantArgumentRule, Builder> {
 
     private Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java
index 18ba2ff..06bd39a 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java
@@ -7,12 +7,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class KeepUnusedArgumentRule extends NoOptimizationBaseRule<KeepUnusedArgumentRule> {
+public class KeepUnusedArgumentRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "keepunusedarguments";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<KeepUnusedArgumentRule, Builder> {
+      extends ProguardConfigurationRule.Builder<KeepUnusedArgumentRule, Builder> {
 
     private Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java b/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java
index 2543285..0bd866d 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java
@@ -8,12 +8,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class KeepUnusedReturnValueRule extends NoOptimizationBaseRule<KeepUnusedReturnValueRule> {
+public class KeepUnusedReturnValueRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "keepunusedreturnvalue";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<KeepUnusedReturnValueRule, Builder> {
+      extends ProguardConfigurationRule.Builder<KeepUnusedReturnValueRule, Builder> {
 
     Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java b/src/main/java/com/android/tools/r8/shaking/NoAccessModificationRule.java
similarity index 64%
copy from src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
copy to src/main/java/com/android/tools/r8/shaking/NoAccessModificationRule.java
index c26832b..aeed6ea 100644
--- a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoAccessModificationRule.java
@@ -1,41 +1,32 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, 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.errors.Unreachable;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class MemberValuePropagationRule extends ProguardConfigurationRule {
+public class NoAccessModificationRule extends ProguardConfigurationRule {
 
-  public enum Type {
-    NEVER
-  }
+  public static final String RULE_NAME = "noaccessmodification";
 
   public static class Builder
-      extends ProguardConfigurationRule.Builder<MemberValuePropagationRule, Builder> {
+      extends ProguardConfigurationRule.Builder<NoAccessModificationRule, Builder> {
 
     private Builder() {
       super();
     }
 
-    Type type;
-
     @Override
-    public Builder self() {
-      return this;
-    }
-
-    public Builder setType(Type type) {
-      this.type = type;
+    public NoAccessModificationRule.Builder self() {
       return this;
     }
 
     @Override
-    public MemberValuePropagationRule build() {
-      return new MemberValuePropagationRule(
+    public NoAccessModificationRule build() {
+      return new NoAccessModificationRule(
           origin,
           getPosition(),
           source,
@@ -48,14 +39,11 @@
           buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
-          memberRules,
-          type);
+          memberRules);
     }
   }
 
-  private final Type type;
-
-  private MemberValuePropagationRule(
+  private NoAccessModificationRule(
       Origin origin,
       Position position,
       String source,
@@ -68,8 +56,7 @@
       List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
-      List<ProguardMemberRule> memberRules,
-      Type type) {
+      List<ProguardMemberRule> memberRules) {
     super(
         origin,
         position,
@@ -84,24 +71,14 @@
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
-    this.type = type;
   }
 
   public static Builder builder() {
     return new Builder();
   }
 
-  public Type getType() {
-    return type;
-  }
-
   @Override
   String typeString() {
-    switch (type) {
-      case NEVER:
-        return "neverpropagatevalue";
-    }
-    throw new Unreachable("Unknown member value propagation type " + type);
+    return RULE_NAME;
   }
-
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/NoMethodStaticizingRule.java b/src/main/java/com/android/tools/r8/shaking/NoMethodStaticizingRule.java
index 84fd67d..54c514b 100644
--- a/src/main/java/com/android/tools/r8/shaking/NoMethodStaticizingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoMethodStaticizingRule.java
@@ -8,12 +8,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class NoMethodStaticizingRule extends NoOptimizationBaseRule<NoMethodStaticizingRule> {
+public class NoMethodStaticizingRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "nomethodstaticizing";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<NoMethodStaticizingRule, Builder> {
+      extends ProguardConfigurationRule.Builder<NoMethodStaticizingRule, Builder> {
 
     Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/NoOptimizationBaseRule.java b/src/main/java/com/android/tools/r8/shaking/NoOptimizationBaseRule.java
deleted file mode 100644
index a397a7e..0000000
--- a/src/main/java/com/android/tools/r8/shaking/NoOptimizationBaseRule.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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 abstract class NoOptimizationBaseRule<R extends NoOptimizationBaseRule<R>>
-    extends ProguardConfigurationRule {
-
-  public abstract static class Builder<R extends NoOptimizationBaseRule<R>, B extends Builder<R, B>>
-      extends ProguardConfigurationRule.Builder<R, B> {
-
-    Builder() {
-      super();
-    }
-  }
-
-  NoOptimizationBaseRule(
-      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);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/shaking/NoParameterReorderingRule.java b/src/main/java/com/android/tools/r8/shaking/NoParameterReorderingRule.java
index c8d0e6c..901b3bc 100644
--- a/src/main/java/com/android/tools/r8/shaking/NoParameterReorderingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoParameterReorderingRule.java
@@ -8,12 +8,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class NoParameterReorderingRule extends NoOptimizationBaseRule<NoParameterReorderingRule> {
+public class NoParameterReorderingRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "noparameterreordering";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<NoParameterReorderingRule, Builder> {
+      extends ProguardConfigurationRule.Builder<NoParameterReorderingRule, Builder> {
 
     Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/NoParameterTypeStrengtheningRule.java b/src/main/java/com/android/tools/r8/shaking/NoParameterTypeStrengtheningRule.java
index e0b6594..172793c 100644
--- a/src/main/java/com/android/tools/r8/shaking/NoParameterTypeStrengtheningRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoParameterTypeStrengtheningRule.java
@@ -8,13 +8,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class NoParameterTypeStrengtheningRule
-    extends NoOptimizationBaseRule<NoParameterTypeStrengtheningRule> {
+public class NoParameterTypeStrengtheningRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "noparametertypestrengthening";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<NoParameterTypeStrengtheningRule, Builder> {
+      extends ProguardConfigurationRule.Builder<NoParameterTypeStrengtheningRule, Builder> {
 
     Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/NoRedundantFieldLoadEliminationRule.java b/src/main/java/com/android/tools/r8/shaking/NoRedundantFieldLoadEliminationRule.java
index 87c5ee0..3921ff1 100644
--- a/src/main/java/com/android/tools/r8/shaking/NoRedundantFieldLoadEliminationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoRedundantFieldLoadEliminationRule.java
@@ -8,13 +8,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class NoRedundantFieldLoadEliminationRule
-    extends NoOptimizationBaseRule<NoRedundantFieldLoadEliminationRule> {
+public class NoRedundantFieldLoadEliminationRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "noredundantfieldloadelimination";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<NoRedundantFieldLoadEliminationRule, Builder> {
+      extends ProguardConfigurationRule.Builder<NoRedundantFieldLoadEliminationRule, Builder> {
 
     Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/NoReturnTypeStrengtheningRule.java b/src/main/java/com/android/tools/r8/shaking/NoReturnTypeStrengtheningRule.java
index 21c6371..11de402 100644
--- a/src/main/java/com/android/tools/r8/shaking/NoReturnTypeStrengtheningRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoReturnTypeStrengtheningRule.java
@@ -8,13 +8,12 @@
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class NoReturnTypeStrengtheningRule
-    extends NoOptimizationBaseRule<NoReturnTypeStrengtheningRule> {
+public class NoReturnTypeStrengtheningRule extends ProguardConfigurationRule {
 
   public static final String RULE_NAME = "noreturntypestrengthening";
 
   public static class Builder
-      extends NoOptimizationBaseRule.Builder<NoReturnTypeStrengtheningRule, Builder> {
+      extends ProguardConfigurationRule.Builder<NoReturnTypeStrengtheningRule, Builder> {
 
     Builder() {
       super();
diff --git a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java b/src/main/java/com/android/tools/r8/shaking/NoValuePropagationRule.java
similarity index 67%
rename from src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
rename to src/main/java/com/android/tools/r8/shaking/NoValuePropagationRule.java
index c26832b..b1ac352 100644
--- a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoValuePropagationRule.java
@@ -3,39 +3,29 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import java.util.List;
 
-public class MemberValuePropagationRule extends ProguardConfigurationRule {
+public class NoValuePropagationRule extends ProguardConfigurationRule {
 
-  public enum Type {
-    NEVER
-  }
+  public static final String RULE_NAME = "neverpropagatevalue";
 
   public static class Builder
-      extends ProguardConfigurationRule.Builder<MemberValuePropagationRule, Builder> {
+      extends ProguardConfigurationRule.Builder<NoValuePropagationRule, Builder> {
 
     private Builder() {
       super();
     }
 
-    Type type;
-
     @Override
     public Builder self() {
       return this;
     }
 
-    public Builder setType(Type type) {
-      this.type = type;
-      return this;
-    }
-
     @Override
-    public MemberValuePropagationRule build() {
-      return new MemberValuePropagationRule(
+    public NoValuePropagationRule build() {
+      return new NoValuePropagationRule(
           origin,
           getPosition(),
           source,
@@ -48,14 +38,11 @@
           buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
-          memberRules,
-          type);
+          memberRules);
     }
   }
 
-  private final Type type;
-
-  private MemberValuePropagationRule(
+  private NoValuePropagationRule(
       Origin origin,
       Position position,
       String source,
@@ -68,8 +55,7 @@
       List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
-      List<ProguardMemberRule> memberRules,
-      Type type) {
+      List<ProguardMemberRule> memberRules) {
     super(
         origin,
         position,
@@ -84,24 +70,14 @@
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
-    this.type = type;
   }
 
   public static Builder builder() {
     return new Builder();
   }
 
-  public Type getType() {
-    return type;
-  }
-
   @Override
   String typeString() {
-    switch (type) {
-      case NEVER:
-        return "neverpropagatevalue";
-    }
-    throw new Unreachable("Unknown member value propagation type " + type);
+    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 2c51922..bec7ae6 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -320,11 +320,12 @@
       } else if (acceptString("keepparameternames")) {
         configurationBuilder.setKeepParameterNames(true, origin, getPosition(optionStart));
       } else if (acceptString("checkdiscard")) {
-        ProguardCheckDiscardRule rule = parseCheckDiscardRule(optionStart);
+        ProguardCheckDiscardRule rule =
+            parseRuleWithClassSpec(optionStart, ProguardCheckDiscardRule.builder());
         configurationBuilder.addRule(rule);
       } else if (acceptString("checkenumstringsdiscarded")) {
         // Not supported, ignore.
-        parseCheckDiscardRule(optionStart);
+        parseRuleWithClassSpec(optionStart, ProguardCheckDiscardRule.builder());
       } else if (acceptString("keepdirectories")) {
         configurationBuilder.enableKeepDirectories();
         parsePathFilter(configurationBuilder::addKeepDirectories);
@@ -332,7 +333,8 @@
         ProguardKeepRule rule = parseKeepRule(optionStart);
         configurationBuilder.addRule(rule);
       } else if (acceptString("whyareyoukeeping")) {
-        ProguardWhyAreYouKeepingRule rule = parseWhyAreYouKeepingRule(optionStart);
+        ProguardWhyAreYouKeepingRule rule =
+            parseRuleWithClassSpec(optionStart, ProguardWhyAreYouKeepingRule.builder());
         configurationBuilder.addRule(rule);
       } else if (acceptString("dontoptimize")) {
         configurationBuilder.disableOptimization();
@@ -458,7 +460,9 @@
             parseFileInputDependency(
                 inputDependencyConsumer::acceptProguardPackageObfuscationDictionary));
       } else if (acceptString("alwaysinline")) {
-        InlineRule rule = parseInlineRule(InlineRule.Type.ALWAYS, optionStart);
+        InlineRule rule =
+            parseRuleWithClassSpec(
+                optionStart, InlineRule.builder().setType(InlineRule.Type.ALWAYS));
         configurationBuilder.addRule(rule);
       } else if (acceptString("adaptclassstrings")) {
         parseClassFilter(configurationBuilder::addAdaptClassStringsPattern);
@@ -467,7 +471,8 @@
       } else if (acceptString("adaptresourcefilecontents")) {
         parsePathFilter(configurationBuilder::addAdaptResourceFileContents);
       } else if (acceptString("identifiernamestring")) {
-        configurationBuilder.addRule(parseIdentifierNameStringRule(optionStart));
+        configurationBuilder.addRule(
+            parseRuleWithClassSpec(optionStart, ProguardIdentifierNameStringRule.builder()));
       } else if (acceptString("if")) {
         configurationBuilder.addRule(parseIfRule(optionStart));
       } else if (acceptString("addconfigurationdebugging")) {
@@ -507,7 +512,8 @@
       }
       if (options.isExperimentalWhyAreYouNotInliningEnabled()) {
         if (acceptString(WhyAreYouNotInliningRule.RULE_NAME)) {
-          configurationBuilder.addRule(parseWhyAreYouNotInliningRule(optionStart));
+          configurationBuilder.addRule(
+              parseRuleWithClassSpec(optionStart, WhyAreYouNotInliningRule.builder()));
           return true;
         }
       }
@@ -525,118 +531,144 @@
         }
         if (acceptString(KeepConstantArgumentRule.RULE_NAME)) {
           KeepConstantArgumentRule rule =
-              parseNoOptimizationRule(optionStart, KeepConstantArgumentRule.builder());
+              parseRuleWithClassSpec(optionStart, KeepConstantArgumentRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(KeepUnusedArgumentRule.RULE_NAME)) {
           KeepUnusedArgumentRule rule =
-              parseNoOptimizationRule(optionStart, KeepUnusedArgumentRule.builder());
+              parseRuleWithClassSpec(optionStart, KeepUnusedArgumentRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(KeepUnusedReturnValueRule.RULE_NAME)) {
           KeepUnusedReturnValueRule rule =
-              parseNoOptimizationRule(optionStart, KeepUnusedReturnValueRule.builder());
+              parseRuleWithClassSpec(optionStart, KeepUnusedReturnValueRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString("alwaysclassinline")) {
-          ClassInlineRule rule = parseClassInlineRule(ClassInlineRule.Type.ALWAYS, optionStart);
+          ClassInlineRule rule =
+              parseRuleWithClassSpec(
+                  optionStart, ClassInlineRule.builder().setType(ClassInlineRule.Type.ALWAYS));
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString("neverclassinline")) {
-          ClassInlineRule rule = parseClassInlineRule(ClassInlineRule.Type.NEVER, optionStart);
+          ClassInlineRule rule =
+              parseRuleWithClassSpec(
+                  optionStart, ClassInlineRule.builder().setType(ClassInlineRule.Type.NEVER));
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString("neverinline")) {
-          InlineRule rule = parseInlineRule(InlineRule.Type.NEVER, optionStart);
+          InlineRule rule =
+              parseRuleWithClassSpec(
+                  optionStart, InlineRule.builder().setType(InlineRule.Type.NEVER));
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString("neversinglecallerinline")) {
-          InlineRule rule = parseInlineRule(InlineRule.Type.NEVER_SINGLE_CALLER, optionStart);
+          InlineRule rule =
+              parseRuleWithClassSpec(
+                  optionStart, InlineRule.builder().setType(InlineRule.Type.NEVER_SINGLE_CALLER));
+          configurationBuilder.addRule(rule);
+          return true;
+        }
+        if (acceptString(NoAccessModificationRule.RULE_NAME)) {
+          NoAccessModificationRule rule =
+              parseRuleWithClassSpec(optionStart, NoAccessModificationRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoFieldTypeStrengtheningRule.RULE_NAME)) {
-          ProguardConfigurationRule rule = parseNoFieldTypeStrengtheningRule(optionStart);
+          NoFieldTypeStrengtheningRule rule =
+              parseRuleWithClassSpec(optionStart, NoFieldTypeStrengtheningRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoUnusedInterfaceRemovalRule.RULE_NAME)) {
-          ProguardConfigurationRule rule = parseNoUnusedInterfaceRemovalRule(optionStart);
+          NoUnusedInterfaceRemovalRule rule =
+              parseRuleWithClassSpec(optionStart, NoUnusedInterfaceRemovalRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoVerticalClassMergingRule.RULE_NAME)) {
-          ProguardConfigurationRule rule = parseNoVerticalClassMergingRule(optionStart);
+          NoVerticalClassMergingRule rule =
+              parseRuleWithClassSpec(optionStart, NoVerticalClassMergingRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoHorizontalClassMergingRule.RULE_NAME)) {
-          ProguardConfigurationRule rule = parseNoHorizontalClassMergingRule(optionStart);
+          NoHorizontalClassMergingRule rule =
+              parseRuleWithClassSpec(optionStart, NoHorizontalClassMergingRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoMethodStaticizingRule.RULE_NAME)) {
-          ProguardConfigurationRule rule =
-              parseNoOptimizationRule(optionStart, NoMethodStaticizingRule.builder());
+          NoMethodStaticizingRule rule =
+              parseRuleWithClassSpec(optionStart, NoMethodStaticizingRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoParameterReorderingRule.RULE_NAME)) {
-          ProguardConfigurationRule rule =
-              parseNoOptimizationRule(optionStart, NoParameterReorderingRule.builder());
+          NoParameterReorderingRule rule =
+              parseRuleWithClassSpec(optionStart, NoParameterReorderingRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoParameterTypeStrengtheningRule.RULE_NAME)) {
-          ProguardConfigurationRule rule =
-              parseNoOptimizationRule(optionStart, NoParameterTypeStrengtheningRule.builder());
+          NoParameterTypeStrengtheningRule rule =
+              parseRuleWithClassSpec(optionStart, NoParameterTypeStrengtheningRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoRedundantFieldLoadEliminationRule.RULE_NAME)) {
-          ProguardConfigurationRule rule =
-              parseNoOptimizationRule(optionStart, NoRedundantFieldLoadEliminationRule.builder());
+          NoRedundantFieldLoadEliminationRule rule =
+              parseRuleWithClassSpec(optionStart, NoRedundantFieldLoadEliminationRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString(NoReturnTypeStrengtheningRule.RULE_NAME)) {
-          ProguardConfigurationRule rule =
-              parseNoOptimizationRule(optionStart, NoReturnTypeStrengtheningRule.builder());
+          NoReturnTypeStrengtheningRule rule =
+              parseRuleWithClassSpec(optionStart, NoReturnTypeStrengtheningRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString("neverpropagatevalue")) {
-          MemberValuePropagationRule rule =
-              parseMemberValuePropagationRule(MemberValuePropagationRule.Type.NEVER, optionStart);
+          NoValuePropagationRule rule =
+              parseRuleWithClassSpec(optionStart, NoValuePropagationRule.builder());
           configurationBuilder.addRule(rule);
           return true;
         }
         if (acceptString("neverreprocessclassinitializer")) {
           configurationBuilder.addRule(
-              parseReprocessClassInitializerRule(
-                  ReprocessClassInitializerRule.Type.NEVER, optionStart));
+              parseRuleWithClassSpec(
+                  optionStart,
+                  ReprocessClassInitializerRule.builder()
+                      .setType(ReprocessClassInitializerRule.Type.NEVER)));
           return true;
         }
         if (acceptString("neverreprocessmethod")) {
           configurationBuilder.addRule(
-              parseReprocessMethodRule(ReprocessMethodRule.Type.NEVER, optionStart));
+              parseRuleWithClassSpec(
+                  optionStart,
+                  ReprocessMethodRule.builder().setType(ReprocessMethodRule.Type.NEVER)));
           return true;
         }
         if (acceptString("reprocessclassinitializer")) {
           configurationBuilder.addRule(
-              parseReprocessClassInitializerRule(
-                  ReprocessClassInitializerRule.Type.ALWAYS, optionStart));
+              parseRuleWithClassSpec(
+                  optionStart,
+                  ReprocessClassInitializerRule.builder()
+                      .setType(ReprocessClassInitializerRule.Type.ALWAYS)));
           return true;
         }
         if (acceptString("reprocessmethod")) {
           configurationBuilder.addRule(
-              parseReprocessMethodRule(ReprocessMethodRule.Type.ALWAYS, optionStart));
+              parseRuleWithClassSpec(
+                  optionStart,
+                  ReprocessMethodRule.builder().setType(ReprocessMethodRule.Type.ALWAYS)));
           return true;
         }
       }
@@ -826,87 +858,8 @@
       return keepRuleBuilder.build();
     }
 
-    private ProguardWhyAreYouKeepingRule parseWhyAreYouKeepingRule(Position start)
-        throws ProguardRuleParserException {
-      ProguardWhyAreYouKeepingRule.Builder keepRuleBuilder = ProguardWhyAreYouKeepingRule.builder()
-          .setOrigin(origin)
-          .setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private ProguardCheckDiscardRule parseCheckDiscardRule(Position start)
-        throws ProguardRuleParserException {
-      ProguardCheckDiscardRule.Builder keepRuleBuilder = ProguardCheckDiscardRule.builder()
-          .setOrigin(origin)
-          .setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private ClassInlineRule parseClassInlineRule(ClassInlineRule.Type type, Position start)
-        throws ProguardRuleParserException {
-      ClassInlineRule.Builder keepRuleBuilder =
-          ClassInlineRule.builder().setOrigin(origin).setStart(start).setType(type);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private NoFieldTypeStrengtheningRule parseNoFieldTypeStrengtheningRule(Position start)
-        throws ProguardRuleParserException {
-      NoFieldTypeStrengtheningRule.Builder keepRuleBuilder =
-          NoFieldTypeStrengtheningRule.builder().setOrigin(origin).setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private NoUnusedInterfaceRemovalRule parseNoUnusedInterfaceRemovalRule(Position start)
-        throws ProguardRuleParserException {
-      NoUnusedInterfaceRemovalRule.Builder keepRuleBuilder =
-          NoUnusedInterfaceRemovalRule.builder().setOrigin(origin).setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private NoVerticalClassMergingRule parseNoVerticalClassMergingRule(Position start)
-        throws ProguardRuleParserException {
-      NoVerticalClassMergingRule.Builder keepRuleBuilder =
-          NoVerticalClassMergingRule.builder().setOrigin(origin).setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private NoHorizontalClassMergingRule parseNoHorizontalClassMergingRule(Position start)
-        throws ProguardRuleParserException {
-      NoHorizontalClassMergingRule.Builder keepRuleBuilder =
-          NoHorizontalClassMergingRule.builder().setOrigin(origin).setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private <R extends NoOptimizationBaseRule<R>, B extends NoOptimizationBaseRule.Builder<R, B>>
-        R parseNoOptimizationRule(Position start, B builder) throws ProguardRuleParserException {
+    private <R extends ProguardConfigurationRule, B extends ProguardConfigurationRule.Builder<R, B>>
+        R parseRuleWithClassSpec(Position start, B builder) throws ProguardRuleParserException {
       builder.setOrigin(origin).setStart(start);
       parseClassSpec(builder);
       Position end = getPosition();
@@ -915,44 +868,6 @@
       return builder.build();
     }
 
-    private MemberValuePropagationRule parseMemberValuePropagationRule(
-        MemberValuePropagationRule.Type type, Position start)
-        throws ProguardRuleParserException {
-      MemberValuePropagationRule .Builder keepRuleBuilder =
-          MemberValuePropagationRule.builder().setOrigin(origin).setStart(start).setType(type);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private InlineRule parseInlineRule(InlineRule.Type type, Position start)
-        throws ProguardRuleParserException {
-      InlineRule.Builder keepRuleBuilder = InlineRule.builder()
-          .setOrigin(origin)
-          .setStart(start)
-          .setType(type);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
-    private ProguardIdentifierNameStringRule parseIdentifierNameStringRule(Position start)
-        throws ProguardRuleParserException {
-      ProguardIdentifierNameStringRule.Builder keepRuleBuilder =
-          ProguardIdentifierNameStringRule.builder()
-              .setOrigin(origin)
-              .setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      Position end = getPosition();
-      keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
-      keepRuleBuilder.setEnd(end);
-      return keepRuleBuilder.build();
-    }
-
     private ProguardIfRule parseIfRule(TextPosition optionStart)
         throws ProguardRuleParserException {
       ProguardIfRule.Builder ifRuleBuilder = ProguardIfRule.builder()
@@ -1018,40 +933,6 @@
       return false;
     }
 
-    private ReprocessClassInitializerRule parseReprocessClassInitializerRule(
-        ReprocessClassInitializerRule.Type type, Position start)
-        throws ProguardRuleParserException {
-      ReprocessClassInitializerRule.Builder builder =
-          ReprocessClassInitializerRule.builder().setOrigin(origin).setStart(start).setType(type);
-      parseClassSpec(builder);
-      Position end = getPosition();
-      builder.setSource(getSourceSnippet(contents, start, end));
-      builder.setEnd(end);
-      return builder.build();
-    }
-
-    private ReprocessMethodRule parseReprocessMethodRule(
-        ReprocessMethodRule.Type type, Position start) throws ProguardRuleParserException {
-      ReprocessMethodRule.Builder builder =
-          ReprocessMethodRule.builder().setOrigin(origin).setStart(start).setType(type);
-      parseClassSpec(builder);
-      Position end = getPosition();
-      builder.setSource(getSourceSnippet(contents, start, end));
-      builder.setEnd(end);
-      return builder.build();
-    }
-
-    private WhyAreYouNotInliningRule parseWhyAreYouNotInliningRule(Position start)
-        throws ProguardRuleParserException {
-      WhyAreYouNotInliningRule.Builder keepRuleBuilder =
-          WhyAreYouNotInliningRule.builder().setOrigin(origin).setStart(start);
-      parseClassSpec(keepRuleBuilder);
-      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/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 192de92..367a2fc 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -273,7 +273,8 @@
         evaluateCheckDiscardRule(clazz, rule.asProguardCheckDiscardRule());
       } else if (rule instanceof CheckEnumUnboxedRule) {
         evaluateCheckEnumUnboxedRule(clazz, (CheckEnumUnboxedRule) rule);
-      } else if (rule instanceof ProguardWhyAreYouKeepingRule) {
+      } else if (rule instanceof NoAccessModificationRule
+          || rule instanceof ProguardWhyAreYouKeepingRule) {
         markClass(clazz, rule, ifRule);
         markMatchingVisibleMethods(clazz, memberKeepRules, rule, null, true, ifRule);
         markMatchingVisibleFields(clazz, memberKeepRules, rule, null, true, ifRule);
@@ -311,7 +312,7 @@
         if (allRulesSatisfied(memberKeepRules, clazz)) {
           markClass(clazz, rule, ifRule);
         }
-      } else if (rule instanceof MemberValuePropagationRule) {
+      } else if (rule instanceof NoValuePropagationRule) {
         markMatchingVisibleMethods(clazz, memberKeepRules, rule, null, true, ifRule);
         markMatchingVisibleFields(clazz, memberKeepRules, rule, null, true, ifRule);
       } else if (rule instanceof ProguardIdentifierNameStringRule) {
@@ -1231,6 +1232,12 @@
             throw new Unreachable();
         }
         context.markAsUsed();
+      } else if (context instanceof NoAccessModificationRule) {
+        assert item.isProgramDefinition();
+        dependentMinimumKeepInfo
+            .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference())
+            .disallowAccessModification();
+        context.markAsUsed();
       } else if (context instanceof NoFieldTypeStrengtheningRule) {
         assert item.isProgramField();
         dependentMinimumKeepInfo
@@ -1282,27 +1289,21 @@
             .asMethodJoiner()
             .disallowReturnTypeStrengthening();
         context.markAsUsed();
-      } else if (context instanceof MemberValuePropagationRule) {
-        switch (((MemberValuePropagationRule) context).getType()) {
-          case NEVER:
-            // Only add members from propgram classes to `neverPropagateValue` since class member
-            // values from library types are not propagated by default.
-            if (item.isField()) {
-              DexClassAndField field = item.asField();
-              if (field.isProgramField()) {
-                neverPropagateValue.add(field.getReference());
-                context.markAsUsed();
-              }
-            } else if (item.isMethod()) {
-              DexClassAndMethod method = item.asMethod();
-              if (method.isProgramMethod()) {
-                neverPropagateValue.add(method.getReference());
-                context.markAsUsed();
-              }
-            }
-            break;
-          default:
-            throw new Unreachable();
+      } else if (context instanceof NoValuePropagationRule) {
+        // Only add members from propgram classes to `neverPropagateValue` since class member values
+        // from library types are not propagated by default.
+        if (item.isField()) {
+          DexClassAndField field = item.asField();
+          if (field.isProgramField()) {
+            neverPropagateValue.add(field.getReference());
+            context.markAsUsed();
+          }
+        } else if (item.isMethod()) {
+          DexClassAndMethod method = item.asMethod();
+          if (method.isProgramMethod()) {
+            neverPropagateValue.add(method.getReference());
+            context.markAsUsed();
+          }
         }
       } else if (context instanceof ProguardIdentifierNameStringRule) {
         evaluateIdentifierNameStringRule(item, context, ifRule);
diff --git a/src/test/java/com/android/tools/r8/NoAccessModification.java b/src/test/java/com/android/tools/r8/NoAccessModification.java
new file mode 100644
index 0000000..4b6fdf3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/NoAccessModification.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2023, 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.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
+public @interface NoAccessModification {}
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index c6f1d08..664ce2e 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.shaking.CheckEnumUnboxedRule;
 import com.android.tools.r8.shaking.CollectingGraphConsumer;
 import com.android.tools.r8.shaking.KeepUnusedReturnValueRule;
+import com.android.tools.r8.shaking.NoAccessModificationRule;
 import com.android.tools.r8.shaking.NoFieldTypeStrengtheningRule;
 import com.android.tools.r8.shaking.NoHorizontalClassMergingRule;
 import com.android.tools.r8.shaking.NoMethodStaticizingRule;
@@ -484,6 +485,10 @@
         "-" + name + " class * { @" + annotation.getTypeName() + " <fields>; }");
   }
 
+  T addInternalMatchAnnotationOnMemberRule(String name, Class<? extends Annotation> annotation) {
+    return addInternalKeepRules("-" + name + " class * { @" + annotation.getTypeName() + " *; }");
+  }
+
   T addInternalMatchAnnotationOnMethodRule(String name, Class<? extends Annotation> annotation) {
     return addInternalKeepRules(
         "-" + name + " class * { @" + annotation.getTypeName() + " <methods>; }");
@@ -550,6 +555,18 @@
             KeepUnusedReturnValueRule.RULE_NAME, KeepUnusedReturnValue.class);
   }
 
+  public T enableNoAccessModificationAnnotationsForClasses() {
+    return addNoAccessModificationAnnotation()
+        .addInternalMatchInterfaceRule(
+            NoAccessModificationRule.RULE_NAME, NoAccessModification.class);
+  }
+
+  public T enableNoAccessModificationAnnotationsForMembers() {
+    return addNoAccessModificationAnnotation()
+        .addInternalMatchAnnotationOnMemberRule(
+            NoAccessModificationRule.RULE_NAME, NoAccessModification.class);
+  }
+
   public T enableNoFieldTypeStrengtheningAnnotations() {
     return addNoFieldTypeStrengtheningAnnotation()
         .addInternalMatchAnnotationOnFieldRule(
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index d9e3f91..cfd2a95 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -512,6 +512,10 @@
     return addTestingAnnotation(NeverSingleCallerInline.class);
   }
 
+  public final T addNoAccessModificationAnnotation() {
+    return addTestingAnnotation(NoAccessModification.class);
+  }
+
   public final T addNoFieldTypeStrengtheningAnnotation() {
     return addTestingAnnotation(NoFieldTypeStrengthening.class);
   }