Introduce option to not trace repeated/one-of fields

Change-Id: Ib36c7ecd5c4ebe15b63a71b53a8b0be165b2aa01
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 6eed002..6db32eb 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -683,7 +683,7 @@
           timing.end();
         }
 
-        if (appView.options().isProtoShrinkingEnabled()) {
+        if (appView.options().protoShrinking().isProtoShrinkingEnabled()) {
           IRConverter converter = new IRConverter(appView, timing, null, mainDexClasses);
 
           // If proto shrinking is enabled, we need to reprocess every dynamicMethod(). This ensures
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index b680cf2..078410a 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -84,7 +84,7 @@
       this.callSiteOptimizationInfoPropagator = null;
     }
 
-    if (enableWholeProgramOptimizations() && options.isProtoShrinkingEnabled()) {
+    if (enableWholeProgramOptimizations() && options.protoShrinking().isProtoShrinkingEnabled()) {
       this.protoShrinker = new ProtoShrinker(withLiveness());
     } else {
       this.protoShrinker = null;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
index 7696a8b..0b4bb94 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -82,7 +82,7 @@
 
   GeneratedExtensionRegistryShrinker(
       AppView<AppInfoWithLiveness> appView, ProtoReferences references) {
-    assert appView.options().enableGeneratedExtensionRegistryShrinking;
+    assert appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking;
     this.appView = appView;
     this.references = references;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoShrinker.java
index 21f8ff9..bd7d362 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoShrinker.java
@@ -22,11 +22,11 @@
     this.decoder = new RawMessageInfoDecoder(factory, references);
     this.factory = factory;
     this.generatedExtensionRegistryShrinker =
-        appView.options().enableGeneratedExtensionRegistryShrinking
+        appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking
             ? new GeneratedExtensionRegistryShrinker(appView, references)
             : null;
     this.generatedMessageLiteShrinker =
-        appView.options().enableGeneratedMessageLiteShrinking
+        appView.options().protoShrinking().enableGeneratedMessageLiteShrinking
             ? new GeneratedMessageLiteShrinker(appView, decoder, references)
             : null;
     this.references = references;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index 5960058..27b3ede 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -352,6 +352,12 @@
       return true;
     }
 
+    if (!appView.options().protoShrinking().traverseOneOfAndRepeatedProtoFields) {
+      if (protoFieldType.isOneOf() || protoFieldType.isRepeated()) {
+        return false;
+      }
+    }
+
     // Otherwise, check if the type of the field may contain a map/required field.
     DexType baseMessageType = protoFieldInfo.getBaseMessageType(factory);
     if (baseMessageType != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldType.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldType.java
index 17f48e4..a9cff43 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldType.java
@@ -99,6 +99,10 @@
     return null;
   }
 
+  public boolean isRepeated() {
+    return !isSingular() && !isMap();
+  }
+
   public boolean isRequired() {
     return isRequired;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoOneOfFieldType.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoOneOfFieldType.java
index 1cc7b97..c476382 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoOneOfFieldType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoOneOfFieldType.java
@@ -38,6 +38,11 @@
   }
 
   @Override
+  public boolean isRepeated() {
+    return false;
+  }
+
+  @Override
   public boolean isSingular() {
     return true;
   }
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 a31a689..fe19510 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -308,7 +308,8 @@
     this.useRegistryFactory = createUseRegistryFactory();
     this.workList = EnqueuerWorklist.createWorklist(appView);
 
-    if (options.enableGeneratedMessageLiteShrinking && mode.isInitialOrFinalTreeShaking()) {
+    if (options.protoShrinking().enableGeneratedMessageLiteShrinking
+        && mode.isInitialOrFinalTreeShaking()) {
       registerAnalysis(new ProtoEnqueuerExtension(appView));
     }
 
@@ -1003,7 +1004,7 @@
       Log.verbose(getClass(), "Register Sget `%s`.", field);
     }
 
-    if (appView.options().enableGeneratedExtensionRegistryShrinking) {
+    if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
       // If it is a dead proto extension field, don't trace onwards.
       boolean skipTracing =
           appView.withGeneratedExtensionRegistryShrinker(
@@ -1048,7 +1049,7 @@
       Log.verbose(getClass(), "Register Sput `%s`.", field);
     }
 
-    if (appView.options().enableGeneratedExtensionRegistryShrinking) {
+    if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
       // If it is a dead proto extension field, don't trace onwards.
       boolean skipTracing =
           appView.withGeneratedExtensionRegistryShrinker(
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 abefde1..2815cb8 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -391,11 +391,6 @@
   public boolean enableLambdaMerging = false;
   // Flag to turn on/off desugaring in D8/R8.
   public boolean enableDesugaring = true;
-  // Flag to turn on/off GeneratedExtensionRegistry shrinking.
-  public boolean enableGeneratedExtensionRegistryShrinking =
-      System.getProperty("com.android.tools.r8.generatedExtensionRegistryShrinking") != null;
-  public boolean enableGeneratedMessageLiteShrinking =
-      System.getProperty("com.android.tools.r8.generatedMessageLiteShrinking") != null;
   // Flag to turn on/off JDK11+ nest-access control
   public boolean enableNestBasedAccessDesugaring = true;
   // Flag to turn on/off reduction of nest to improve class merging optimizations.
@@ -444,6 +439,8 @@
   public boolean skipIR = false;
 
   public boolean debug = false;
+
+  private final ProtoShrinkingOptions protoShrinking = new ProtoShrinkingOptions();
   public final TestingOptions testing = new TestingOptions();
 
   public List<ProguardConfigurationRule> mainDexKeepRules = ImmutableList.of();
@@ -459,6 +456,10 @@
 
   public LineNumberOptimization lineNumberOptimization = LineNumberOptimization.ON;
 
+  public ProtoShrinkingOptions protoShrinking() {
+    return protoShrinking;
+  }
+
   public static boolean shouldEnableKeepRuleSynthesisForRecompilation() {
     return System.getProperty("com.android.tools.r8.keepRuleSynthesisForRecompilation") != null;
   }
@@ -921,6 +922,22 @@
     public int threshold = 20;
   }
 
+  public static class ProtoShrinkingOptions {
+
+    public boolean enableGeneratedExtensionRegistryShrinking =
+        System.getProperty("com.android.tools.r8.generatedExtensionRegistryShrinking") != null;
+
+    public boolean enableGeneratedMessageLiteShrinking =
+        System.getProperty("com.android.tools.r8.generatedMessageLiteShrinking") != null;
+
+    public boolean traverseOneOfAndRepeatedProtoFields =
+        System.getProperty("com.android.tools.r8.traverseOneOfAndRepeatedProtoFields") == null;
+
+    public boolean isProtoShrinkingEnabled() {
+      return enableGeneratedExtensionRegistryShrinking || enableGeneratedMessageLiteShrinking;
+    }
+  }
+
   public static class TestingOptions {
 
     public static int NO_LIMIT = -1;
@@ -1088,10 +1105,6 @@
     return enableStringSwitchConversion && !debug;
   }
 
-  public boolean isProtoShrinkingEnabled() {
-    return enableGeneratedExtensionRegistryShrinking || enableGeneratedMessageLiteShrinking;
-  }
-
   public boolean canUseMultidex() {
     assert isGeneratingDex();
     return intermediate || hasMinApi(AndroidApiLevel.L);
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java
index 95004d5..f29c397 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java
@@ -51,11 +51,14 @@
                   assert !options.enableFieldBitAccessAnalysis;
                   options.enableFieldBitAccessAnalysis = true;
 
-                  assert !options.enableGeneratedExtensionRegistryShrinking;
-                  options.enableGeneratedExtensionRegistryShrinking = true;
+                  assert !options.protoShrinking().enableGeneratedExtensionRegistryShrinking;
+                  options.protoShrinking().enableGeneratedExtensionRegistryShrinking = true;
 
-                  assert !options.enableGeneratedMessageLiteShrinking;
-                  options.enableGeneratedMessageLiteShrinking = true;
+                  assert !options.protoShrinking().enableGeneratedMessageLiteShrinking;
+                  options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
+
+                  assert options.protoShrinking().traverseOneOfAndRepeatedProtoFields;
+                  options.protoShrinking().traverseOneOfAndRepeatedProtoFields = false;
 
                   assert !options.enableStringSwitchConversion;
                   options.enableStringSwitchConversion = true;
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
index 272f60b..07ccabd 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
@@ -54,8 +54,8 @@
         .addOptionsModification(
             options -> {
               options.enableFieldBitAccessAnalysis = true;
-              options.enableGeneratedMessageLiteShrinking = true;
-              options.enableGeneratedExtensionRegistryShrinking = true;
+              options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
+              options.protoShrinking().enableGeneratedExtensionRegistryShrinking = true;
               options.enableStringSwitchConversion = true;
             })
         .allowAccessModification()
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
index cbd92b0..506e33a 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
@@ -82,8 +82,8 @@
             .addOptionsModification(
                 options -> {
                   options.enableFieldBitAccessAnalysis = true;
-                  options.enableGeneratedMessageLiteShrinking = true;
-                  options.enableGeneratedExtensionRegistryShrinking = true;
+                  options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
+                  options.protoShrinking().enableGeneratedExtensionRegistryShrinking = true;
                   options.enableStringSwitchConversion = true;
 
                   // TODO(b/144003629): If devirtualization is enabled, then we insert a cast to
@@ -366,8 +366,8 @@
         // Enable the dynamicMethod() rewritings.
         .addOptionsModification(
             options -> {
-              assert !options.enableGeneratedMessageLiteShrinking;
-              options.enableGeneratedMessageLiteShrinking = true;
+              assert !options.protoShrinking().enableGeneratedMessageLiteShrinking;
+              options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
             })
         .allowAccessModification(allowAccessModification)
         .allowUnusedProguardConfigurationRules()
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
index ce3bc4e..2a4b79e 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
@@ -57,8 +57,8 @@
         .addKeepRuleFiles(PROTOBUF_LITE_PROGUARD_RULES)
         .addOptionsModification(
             options -> {
-              options.enableGeneratedMessageLiteShrinking = true;
-              options.enableGeneratedExtensionRegistryShrinking = true;
+              options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
+              options.protoShrinking().enableGeneratedExtensionRegistryShrinking = true;
               options.enableStringSwitchConversion = true;
             })
         .allowAccessModification(allowAccessModification)
@@ -107,8 +107,8 @@
         // Enable the dynamicMethod() rewritings.
         .addOptionsModification(
             options -> {
-              assert !options.enableGeneratedMessageLiteShrinking;
-              options.enableGeneratedMessageLiteShrinking = true;
+              assert !options.protoShrinking().enableGeneratedMessageLiteShrinking;
+              options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
             })
         .allowAccessModification(allowAccessModification)
         .allowUnusedProguardConfigurationRules()
diff --git a/src/test/java/com/android/tools/r8/internal/proto/YouTubeProtoRewritingTest.java b/src/test/java/com/android/tools/r8/internal/proto/YouTubeProtoRewritingTest.java
index e0b4250..cff1e45 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/YouTubeProtoRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/YouTubeProtoRewritingTest.java
@@ -49,8 +49,8 @@
         // Enable the dynamicMethod() rewritings.
         .addOptionsModification(
             options -> {
-              assert !options.enableGeneratedMessageLiteShrinking;
-              options.enableGeneratedMessageLiteShrinking = true;
+              assert !options.protoShrinking().enableGeneratedMessageLiteShrinking;
+              options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
             })
         .allowUnusedProguardConfigurationRules()
         .compile()
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
index f659abe..7c40d1e 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
@@ -101,7 +101,9 @@
     FieldSignature lookupSignature = new FieldSignature(signature.name, fieldType);
 
     MemberNaming memberNaming = clazz.naming.lookup(lookupSignature);
-    return memberNaming != null ? (FieldSignature) memberNaming.getOriginalSignature() : signature;
+    return memberNaming != null
+        ? (FieldSignature) memberNaming.getOriginalSignature()
+        : lookupSignature;
   }
 
   public DexField getOriginalDexField(DexItemFactory dexItemFactory) {
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 28c0634..0415a52 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -491,6 +491,7 @@
       extra_args.append('-Dcom.android.tools.r8.generatedExtensionRegistryShrinking=1')
       extra_args.append('-Dcom.android.tools.r8.generatedMessageLiteShrinking=1')
       extra_args.append('-Dcom.android.tools.r8.stringSwitchConversion=1')
+      extra_args.append('-Dcom.android.tools.r8.traverseOneOfAndRepeatedProtoFields=0')
 
   if (not options.no_libraries and 'libraries' in values
       and 'no_inputs_in_pgconf' in values and not values['no_inputs_in_pgconf']):