Class inlining of extendable proto builders
Change-Id: I88ff67f879b4a7dbcc9e9a9addb4042f5ca241f8
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index 552fa07..e2881ad 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
@@ -60,11 +59,17 @@
public static void addInliningHeuristicsForBuilderInlining(
AppView<? extends AppInfoWithSubtyping> appView,
PredicateSet<DexType> alwaysClassInline,
+ Set<DexType> neverMerge,
Set<DexMethod> alwaysInline,
Set<DexMethod> neverInline,
Set<DexMethod> bypassClinitforInlining) {
new RootSetExtension(
- appView, alwaysClassInline, alwaysInline, neverInline, bypassClinitforInlining)
+ appView,
+ alwaysClassInline,
+ neverMerge,
+ alwaysInline,
+ neverInline,
+ bypassClinitforInlining)
.extend();
}
@@ -181,6 +186,8 @@
private final ProtoReferences references;
private final PredicateSet<DexType> alwaysClassInline;
+ private final Set<DexType> neverMerge;
+
private final Set<DexMethod> alwaysInline;
private final Set<DexMethod> neverInline;
private final Set<DexMethod> bypassClinitforInlining;
@@ -188,12 +195,14 @@
RootSetExtension(
AppView<? extends AppInfoWithSubtyping> appView,
PredicateSet<DexType> alwaysClassInline,
+ Set<DexType> neverMerge,
Set<DexMethod> alwaysInline,
Set<DexMethod> neverInline,
Set<DexMethod> bypassClinitforInlining) {
this.appView = appView;
this.references = appView.protoShrinker().references;
this.alwaysClassInline = alwaysClassInline;
+ this.neverMerge = neverMerge;
this.alwaysInline = alwaysInline;
this.neverInline = neverInline;
this.bypassClinitforInlining = bypassClinitforInlining;
@@ -208,10 +217,10 @@
// * extends GeneratedMessageLite heuristics.
bypassClinitforInliningNewBuilderMethods();
- alwaysInlineDynamicMethodFromGeneratedMessageLiteImplementations();
// GeneratedMessageLite$Builder heuristics.
- alwaysInlineBuildPartialFromGeneratedMessageLiteBuilder();
+ alwaysInlineBuildPartialFromGeneratedMessageLiteExtendableBuilder();
+ neverMergeGeneratedMessageLiteBuilder();
}
private void alwaysClassInlineGeneratedMessageLiteBuilders() {
@@ -236,29 +245,20 @@
}
}
- private void alwaysInlineBuildPartialFromGeneratedMessageLiteBuilder() {
- alwaysInline.add(references.generatedMessageLiteBuilderMethods.buildPartialMethod);
+ private void alwaysInlineBuildPartialFromGeneratedMessageLiteExtendableBuilder() {
+ alwaysInline.add(references.generatedMessageLiteExtendableBuilderMethods.buildPartialMethod);
}
private void alwaysInlineCreateBuilderFromGeneratedMessageLite() {
alwaysInline.add(references.generatedMessageLiteMethods.createBuilderMethod);
}
- private void alwaysInlineDynamicMethodFromGeneratedMessageLiteImplementations() {
- // TODO(b/132600418): We should be able to determine that dynamicMethod() becomes 'SIMPLE'
- // when the MethodToInvoke argument is MethodToInvoke.NEW_BUILDER.
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- for (DexType type : appView.appInfo().subtypes(references.generatedMessageLiteType)) {
- alwaysInline.add(
- dexItemFactory.createMethod(
- type,
- dexItemFactory.createProto(
- dexItemFactory.objectType,
- references.methodToInvokeType,
- dexItemFactory.objectType,
- dexItemFactory.objectType),
- "dynamicMethod"));
- }
+ private void neverMergeGeneratedMessageLiteBuilder() {
+ // For consistency, never merge the GeneratedMessageLite builders. These will only have a
+ // unique subtype if the application has a single proto message, which mostly happens during
+ // testing.
+ neverMerge.add(references.generatedMessageLiteBuilderType);
+ neverMerge.add(references.generatedMessageLiteExtendableBuilderType);
}
/**
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java
index 56fd8e9..de37f38 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.ir.analysis.proto.ProtoReferences.MethodToInvokeMembers;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -22,19 +23,30 @@
private static final int METHOD_TO_INVOKE_ARGUMENT_POSITION_IN_DYNAMIC_METHOD = 1;
+ private final AppView<?> appView;
private final InliningReasonStrategy parent;
private final ProtoReferences references;
public ProtoInliningReasonStrategy(AppView<?> appView, InliningReasonStrategy parent) {
+ this.appView = appView;
this.parent = parent;
this.references = appView.protoShrinker().references;
}
@Override
- public Reason computeInliningReason(InvokeMethod invoke, DexEncodedMethod target) {
+ public Reason computeInliningReason(
+ InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context) {
+ DexProgramClass enclosingClass = appView.definitionFor(context.method.holder).asProgramClass();
+ if (references.isAbstractGeneratedMessageLiteBuilder(enclosingClass)
+ && invoke.isInvokeSuper()) {
+ // Aggressively inline invoke-super calls inside the GeneratedMessageLite builders. Such
+ // instructions prohibit inlining of the enclosing method into other contexts, and therefore
+ // block class inlining of proto builders.
+ return Reason.ALWAYS;
+ }
return references.isDynamicMethod(target) || references.isDynamicMethodBridge(target)
? computeInliningReasonForDynamicMethod(invoke)
- : parent.computeInliningReason(invoke, target);
+ : parent.computeInliningReason(invoke, target, context);
}
private Reason computeInliningReasonForDynamicMethod(InvokeMethod invoke) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
index aaf3483..aacb2a0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
@@ -21,12 +21,15 @@
public final DexType generatedExtensionType;
public final DexType generatedMessageLiteType;
public final DexType generatedMessageLiteBuilderType;
+ public final DexType generatedMessageLiteExtendableBuilderType;
public final DexType rawMessageInfoType;
public final DexType messageLiteType;
public final DexType methodToInvokeType;
public final GeneratedMessageLiteMethods generatedMessageLiteMethods;
public final GeneratedMessageLiteBuilderMethods generatedMessageLiteBuilderMethods;
+ public final GeneratedMessageLiteExtendableBuilderMethods
+ generatedMessageLiteExtendableBuilderMethods;
public final MethodToInvokeMembers methodToInvokeMembers;
public final DexString dynamicMethodName;
@@ -54,6 +57,9 @@
generatedMessageLiteBuilderType =
factory.createType(
factory.createString("Lcom/google/protobuf/GeneratedMessageLite$Builder;"));
+ generatedMessageLiteExtendableBuilderType =
+ factory.createType(
+ factory.createString("Lcom/google/protobuf/GeneratedMessageLite$ExtendableBuilder;"));
rawMessageInfoType =
factory.createType(factory.createString("Lcom/google/protobuf/RawMessageInfo;"));
messageLiteType = factory.createType(factory.createString("Lcom/google/protobuf/MessageLite;"));
@@ -89,9 +95,16 @@
generatedMessageLiteMethods = new GeneratedMessageLiteMethods(factory);
generatedMessageLiteBuilderMethods = new GeneratedMessageLiteBuilderMethods(factory);
+ generatedMessageLiteExtendableBuilderMethods =
+ new GeneratedMessageLiteExtendableBuilderMethods(factory);
methodToInvokeMembers = new MethodToInvokeMembers(factory);
}
+ public boolean isAbstractGeneratedMessageLiteBuilder(DexProgramClass clazz) {
+ return clazz.type == generatedMessageLiteBuilderType
+ || clazz.type == generatedMessageLiteExtendableBuilderType;
+ }
+
public boolean isDynamicMethod(DexMethod method) {
return method.name == dynamicMethodName && method.proto == dynamicMethodProto;
}
@@ -114,7 +127,9 @@
}
public boolean isGeneratedMessageLiteBuilder(DexProgramClass clazz) {
- return clazz.superType == generatedMessageLiteBuilderType;
+ return (clazz.superType == generatedMessageLiteBuilderType
+ || clazz.superType == generatedMessageLiteExtendableBuilderType)
+ && !isAbstractGeneratedMessageLiteBuilder(clazz);
}
public boolean isMessageInfoConstructionMethod(DexMethod method) {
@@ -165,6 +180,19 @@
}
}
+ class GeneratedMessageLiteExtendableBuilderMethods {
+
+ public final DexMethod buildPartialMethod;
+
+ private GeneratedMessageLiteExtendableBuilderMethods(DexItemFactory dexItemFactory) {
+ buildPartialMethod =
+ dexItemFactory.createMethod(
+ generatedMessageLiteExtendableBuilderType,
+ dexItemFactory.createProto(extendableMessageType),
+ "buildPartial");
+ }
+ }
+
public class MethodToInvokeMembers {
public final DexField buildMessageInfoField;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 145bb62..8370b69 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -325,6 +325,7 @@
public InlineAction computeInlining(
InvokeMethod invoke,
DexEncodedMethod singleTarget,
+ DexEncodedMethod context,
ClassInitializationAnalysis classInitializationAnalysis,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
if (isSingleTargetInvalid(invoke, singleTarget, whyAreYouNotInliningReporter)) {
@@ -335,7 +336,7 @@
return null;
}
- Reason reason = reasonStrategy.computeInliningReason(invoke, singleTarget);
+ Reason reason = reasonStrategy.computeInliningReason(invoke, singleTarget, context);
if (reason == Reason.NEVER) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
index 15281a5..26c28d7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
@@ -61,6 +61,7 @@
public InlineAction computeInlining(
InvokeMethod invoke,
DexEncodedMethod singleTarget,
+ DexEncodedMethod context,
ClassInitializationAnalysis classInitializationAnalysis,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
return computeForInvoke(invoke, whyAreYouNotInliningReporter);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index eeff808..5bbc662 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -948,7 +948,11 @@
: WhyAreYouNotInliningReporter.createFor(singleTarget, appView, context);
InlineAction action =
oracle.computeInlining(
- invoke, singleTarget, classInitializationAnalysis, whyAreYouNotInliningReporter);
+ invoke,
+ singleTarget,
+ context,
+ classInitializationAnalysis,
+ whyAreYouNotInliningReporter);
if (action == null) {
assert whyAreYouNotInliningReporter.unsetReasonHasBeenReportedFlag();
continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 3fbb76f..6f4570f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -31,6 +31,7 @@
InlineAction computeInlining(
InvokeMethod invoke,
DexEncodedMethod singleTarget,
+ DexEncodedMethod context,
ClassInitializationAnalysis classInitializationAnalysis,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 50c0d30..a5b8d52 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -1112,6 +1112,7 @@
oracle.computeInlining(
invoke,
singleTarget,
+ method,
ClassInitializationAnalysis.trivial(),
NopWhyAreYouNotInliningReporter.getInstance());
if (inlineAction == null) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java
index f28afbe..5c45a37 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java
@@ -28,7 +28,8 @@
}
@Override
- public Reason computeInliningReason(InvokeMethod invoke, DexEncodedMethod target) {
+ public Reason computeInliningReason(
+ InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context) {
if (target.getOptimizationInfo().forceInline()
|| (appView.appInfo().hasLiveness()
&& appView.withLiveness().appInfo().forceInline.contains(target.method))) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java
index 90fc4f0..2b4c072 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java
@@ -17,7 +17,8 @@
}
@Override
- public Reason computeInliningReason(InvokeMethod invoke, DexEncodedMethod target) {
+ public Reason computeInliningReason(
+ InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context) {
return reason;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java
index 5450988..6e8e1aa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java
@@ -10,5 +10,6 @@
public interface InliningReasonStrategy {
- Reason computeInliningReason(InvokeMethod invoke, DexEncodedMethod target);
+ Reason computeInliningReason(
+ InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context);
}
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 62a0553..f27bd26 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -296,7 +296,12 @@
}
if (appView.options().protoShrinking().enableGeneratedMessageLiteBuilderShrinking) {
GeneratedMessageLiteBuilderShrinker.addInliningHeuristicsForBuilderInlining(
- appView, alwaysClassInline, alwaysInline, neverInline, bypassClinitforInlining);
+ appView,
+ alwaysClassInline,
+ neverMerge,
+ alwaysInline,
+ neverInline,
+ bypassClinitforInlining);
}
assert Sets.intersection(neverInline, alwaysInline).isEmpty()
&& Sets.intersection(neverInline, forceInline).isEmpty()
diff --git a/src/test/examplesProto/proto2/HasFlaggedOffExtensionBuilderTestClass.java b/src/test/examplesProto/proto2/HasFlaggedOffExtensionBuilderTestClass.java
new file mode 100644
index 0000000..9cc9e84
--- /dev/null
+++ b/src/test/examplesProto/proto2/HasFlaggedOffExtensionBuilderTestClass.java
@@ -0,0 +1,45 @@
+// 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 proto2;
+
+import com.android.tools.r8.proto2.Shrinking.HasFlaggedOffExtension;
+import com.google.protobuf.ExtensionRegistryLite;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.WireFormat;
+import java.nio.ByteBuffer;
+
+public class HasFlaggedOffExtensionBuilderTestClass {
+
+ // A protobuf payload indicating that varint field 1 is set to 42.
+ // See https://developers.google.com/protocol-buffers/docs/encoding
+ //
+ // Since serialization and deserialization use the same schema (which we're modifying), testing
+ // against wire-format data is preferred.
+ private static final byte[] FIELD1_SET_TO_42 =
+ new byte[] {(1 << 3) | WireFormat.WIRETYPE_VARINT, 42};
+
+ // A protobuf payload indicating that field 10 is a message whose field 1 is set to 42.
+ private static final byte[] MESSAGE10_WITH_FIELD1_SET_TO_42 =
+ ByteBuffer.allocate(4)
+ .put(
+ new byte[] {
+ (10 << 3) | WireFormat.WIRETYPE_LENGTH_DELIMITED, (byte) FIELD1_SET_TO_42.length
+ })
+ .put(FIELD1_SET_TO_42)
+ .array();
+
+ public static void main(String[] args) {
+ HasFlaggedOffExtension msg;
+ try {
+ msg =
+ HasFlaggedOffExtension.parseFrom(
+ MESSAGE10_WITH_FIELD1_SET_TO_42, ExtensionRegistryLite.getGeneratedRegistry());
+ } catch (InvalidProtocolBufferException e) {
+ System.out.println("Unexpected exception: " + e);
+ throw new RuntimeException(e);
+ }
+ Printer.print(HasFlaggedOffExtension.newBuilder(msg).build());
+ }
+}
diff --git a/src/test/examplesProto/proto2/Printer.java b/src/test/examplesProto/proto2/Printer.java
index fd87ef0..0d6f506 100644
--- a/src/test/examplesProto/proto2/Printer.java
+++ b/src/test/examplesProto/proto2/Printer.java
@@ -4,20 +4,25 @@
package proto2;
+import com.android.tools.r8.proto2.Shrinking.HasFlaggedOffExtension;
import com.android.tools.r8.proto2.TestProto.Primitives;
public class Printer {
- static void print(Primitives primitives) {
- System.out.println(primitives.hasFooInt32());
- System.out.println(primitives.getFooInt32());
- System.out.println(primitives.hasOneofString());
- System.out.println(primitives.getOneofString());
- System.out.println(primitives.hasOneofUint32());
- System.out.println(primitives.getOneofUint32());
- System.out.println(primitives.hasBarInt64());
- System.out.println(primitives.getBarInt64());
- System.out.println(primitives.hasQuxString());
- System.out.println(primitives.getQuxString());
+ static void print(HasFlaggedOffExtension msg) {
+ System.out.println(msg.getSerializedSize());
+ }
+
+ static void print(Primitives msg) {
+ System.out.println(msg.hasFooInt32());
+ System.out.println(msg.getFooInt32());
+ System.out.println(msg.hasOneofString());
+ System.out.println(msg.getOneofString());
+ System.out.println(msg.hasOneofUint32());
+ System.out.println(msg.getOneofUint32());
+ System.out.println(msg.hasBarInt64());
+ System.out.println(msg.getBarInt64());
+ System.out.println(msg.hasQuxString());
+ System.out.println(msg.getQuxString());
}
}
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 b17cae5..6bf5d8f 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
@@ -47,12 +47,14 @@
ImmutableList.of("proto2.BuilderWithProtoBuilderSetterTestClass"),
ImmutableList.of("proto2.BuilderWithProtoSetterTestClass"),
ImmutableList.of("proto2.BuilderWithReusedSettersTestClass"),
+ ImmutableList.of("proto2.HasFlaggedOffExtensionBuilderTestClass"),
ImmutableList.of(
"proto2.BuilderWithOneofSetterTestClass",
"proto2.BuilderWithPrimitiveSettersTestClass",
"proto2.BuilderWithProtoBuilderSetterTestClass",
"proto2.BuilderWithProtoSetterTestClass",
- "proto2.BuilderWithReusedSettersTestClass")),
+ "proto2.BuilderWithReusedSettersTestClass",
+ "proto2.HasFlaggedOffExtensionBuilderTestClass")),
getTestParameters().withAllRuntimesAndApiLevels().build());
}
@@ -70,11 +72,22 @@
.addKeepRuleFiles(PROTOBUF_LITE_PROGUARD_RULES)
.addOptionsModification(
options -> {
+ assert !options.applyInliningToInlinee;
options.applyInliningToInlinee = true;
+
+ assert !options.enableFieldBitAccessAnalysis;
options.enableFieldBitAccessAnalysis = true;
+
+ assert !options.protoShrinking().enableGeneratedExtensionRegistryShrinking;
options.protoShrinking().enableGeneratedExtensionRegistryShrinking = true;
+
+ assert !options.protoShrinking().enableGeneratedMessageLiteShrinking;
options.protoShrinking().enableGeneratedMessageLiteShrinking = true;
+
+ assert !options.protoShrinking().enableGeneratedMessageLiteBuilderShrinking;
options.protoShrinking().enableGeneratedMessageLiteBuilderShrinking = true;
+
+ assert !options.enableStringSwitchConversion;
options.enableStringSwitchConversion = true;
})
.allowAccessModification()
@@ -154,6 +167,8 @@
"0",
"true",
"qux");
+ case "proto2.HasFlaggedOffExtensionBuilderTestClass":
+ return StringUtils.lines("4");
default:
throw new Unreachable();
}
@@ -166,6 +181,12 @@
private void verifyBuildersAreAbsent(CodeInspector outputInspector) {
assertThat(
+ outputInspector.clazz(
+ "com.android.tools.r8.proto2.Shrinking$HasFlaggedOffExtension$Builder"),
+ mains.equals(ImmutableList.of("proto2.HasFlaggedOffExtensionBuilderTestClass"))
+ ? isPresent()
+ : not(isPresent()));
+ assertThat(
outputInspector.clazz("com.android.tools.r8.proto2.TestProto$Primitives$Builder"),
not(isPresent()));
assertThat(