[vm] Make the protobuf aware treeshaker robust against name mangling

Before we used the literal name to discover accessors related to a field.
This will fail when the name has been mangled to be a valid Dart
identifier in the given scope.

This requires: https://github.com/dart-lang/protobuf/pull/282 and a DEPS
update to work.

Bug: https://buganizer.corp.google.com/issues/132616050
Change-Id: I2950402d072a772b887e53953916cfe3669456b1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/116208
Commit-Queue: Sigurd Meldgaard <sigurdm@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Sigurd Meldgaard 2019-10-24 06:48:23 +00:00 committed by commit-bot@chromium.org
parent 86af66a3ee
commit 539c10b4d1
9 changed files with 399 additions and 165 deletions

6
DEPS
View file

@ -56,7 +56,7 @@ vars = {
# Revisions of /third_party/* dependencies.
"args_tag": "1.5.0",
"async_tag": "2.0.8",
"bazel_worker_tag": "bazel_worker-v0.1.20",
"bazel_worker_tag": "v0.1.22",
"benchmark_harness_tag": "81641290dea44c34138a109a37e215482f405f81",
"boolean_selector_tag" : "1.0.4",
"boringssl_gen_rev": "b9e27cff1ff0803e97ab1f88764a83be4aa94a6d",
@ -117,7 +117,7 @@ vars = {
"pedantic_tag": "v1.8.0",
"ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
"pool_tag": "1.3.6",
"protobuf_rev": "7d34c9e4e552a4f66acce32e4344ae27756a1949",
"protobuf_rev": "3746c8fd3f2b0147623a8e3db89c3ff4330de760",
"pub_rev": "df0f72daaa724e29ed6075e0fb5549a6d6dc5daf",
"pub_semver_tag": "1.4.2",
"quiver-dart_tag": "2.0.0+1",
@ -342,7 +342,7 @@ deps = {
Var("dart_root") + "/third_party/pkg/pool":
Var("dart_git") + "pool.git" + "@" + Var("pool_tag"),
Var("dart_root") + "/third_party/pkg/protobuf":
Var("dart_git") + "protobuf.git" + "@" + Var("protobuf_rev"),
Var("dart_git") + "protobuf.git" + "@" + Var("protobuf_rev"),
Var("dart_root") + "/third_party/pkg/pub_semver":
Var("dart_git") + "pub_semver.git" + "@" + Var("pub_semver_tag"),
Var("dart_root") + "/third_party/pkg/pub":

View file

@ -62,6 +62,9 @@ InfoCollector removeUnusedProtoReferences(
final gmClass = protobufLib.classes
.where((klass) => klass.name == 'GeneratedMessage')
.single;
final tagNumberClass =
protobufLib.classes.where((klass) => klass.name == 'TagNumber').single;
final collector = InfoCollector(gmClass);
final biClass =
@ -71,8 +74,8 @@ InfoCollector removeUnusedProtoReferences(
component.accept(collector);
_UnusedFieldMetadataPruner(
biClass, addMethod, collector.dynamicSelectors, coreTypes, info)
_UnusedFieldMetadataPruner(tagNumberClass, biClass, addMethod,
collector.dynamicSelectors, coreTypes, info)
.removeMetadataForUnusedFields(
collector.gmSubclasses,
collector.gmSubclassesInvokedMethods,
@ -85,6 +88,8 @@ InfoCollector removeUnusedProtoReferences(
/// For protobuf fields which are not accessed, prune away its metadata.
class _UnusedFieldMetadataPruner extends TreeVisitor<void> {
final Class tagNumberClass;
final Reference tagNumberField;
// All of those methods have the dart field name as second positional
// parameter.
// Method names are defined in:
@ -93,26 +98,34 @@ class _UnusedFieldMetadataPruner extends TreeVisitor<void> {
// https://github.com/dart-lang/protobuf/blob/master/protoc_plugin/lib/protobuf_field.dart.
static final fieldAddingMethods = Set<String>.from(const <String>[
'a',
'm',
'pp',
'pc',
'e',
'pc',
'aOM',
'aOS',
'aQM',
'pPS',
'aQS',
'aInt64',
'aOB',
'e',
'p',
'pc',
'm',
]);
final Class builderInfoClass;
Class visitedClass;
final names = Set<String>();
final usedTagNumbers = Set<int>();
final dynamicNames = Set<String>();
final CoreTypes coreTypes;
final TransformationInfo info;
final Member addMethod;
_UnusedFieldMetadataPruner(this.builderInfoClass, this.addMethod,
Set<Selector> dynamicSelectors, this.coreTypes, this.info) {
_UnusedFieldMetadataPruner(this.tagNumberClass, this.builderInfoClass,
this.addMethod, Set<Selector> dynamicSelectors, this.coreTypes, this.info)
: tagNumberField = tagNumberClass.fields
.firstWhere((f) => f.name.name == 'tagNumber')
.reference {
dynamicNames.addAll(dynamicSelectors.map((sel) => sel.target.name));
}
@ -140,30 +153,58 @@ class _UnusedFieldMetadataPruner extends TreeVisitor<void> {
names.clear();
names.addAll(selectors.map((sel) => sel.target.name));
visitedClass = gmSubclass;
_computeUsedTagNumbers(gmSubclass);
field.initializer.accept(this);
}
void _computeUsedTagNumbers(Class gmSubclass) {
usedTagNumbers.clear();
for (final procedure in gmSubclass.procedures) {
for (final annotation in procedure.annotations) {
if (annotation is ConstantExpression) {
final constant = annotation.constant;
if (constant is InstanceConstant &&
constant.classReference == tagNumberClass.reference) {
final name = procedure.canonicalName.name;
if (dynamicNames.contains(name) || names.contains(name)) {
usedTagNumbers.add(
(constant.fieldValues[tagNumberField] as IntConstant).value);
}
}
}
}
}
}
@override
visitLet(Let node) {
// The BuilderInfo field `_i` is set up with a row of cascaded calls.
// ```
// static final BuilderInfo _i = BuilderInfo('MessageName')
// ..a(1, 'foo', PbFieldType.OM)
// ..a(2, 'bar', PbFieldType.OM)
// ```
// Each cascaded call will be represented in kernel as a let, where the
// initializer will be a call to a method of `builderInfo`. For example:
// ```
// {protobuf::BuilderInfo::a}<dart.core::int*>(1, "foo", #C10)
// ```
// The methods enumerated in `fieldAddingMethods` are the ones that set up
// fields (other methods do other things).
//
// First argument is the tag-number of the added field.
// Second argument is the field-name.
// Further arguments are specific to the method.
final initializer = node.variable.initializer;
if (initializer is MethodInvocation &&
initializer.interfaceTarget?.enclosingClass == builderInfoClass &&
fieldAddingMethods.contains(initializer.name.name)) {
final fieldName =
(initializer.arguments.positional[1] as StringLiteral).value;
final ucase = fieldName[0].toUpperCase() + fieldName.substring(1);
// The name of the related `clear` method.
final clearName = 'clear${ucase}';
// The name of the related `has` method.
final hasName = 'has${ucase}';
bool nameIsUsed(String name) =>
dynamicNames.contains(name) || names.contains(name);
if (!(nameIsUsed(fieldName) ||
nameIsUsed(clearName) ||
nameIsUsed(hasName))) {
final tagNumber =
(initializer.arguments.positional[0] as IntLiteral).value;
if (!usedTagNumbers.contains(tagNumber)) {
if (info != null) {
final fieldName =
(initializer.arguments.positional[1] as StringLiteral).value;
info.removedMessageFields.add("${visitedClass.name}.$fieldName");
}

View file

@ -36,7 +36,8 @@ runTestCase(Uri source) async {
for (Class messageClass in messageClasses) {
expect(messageClass.enclosingLibrary.classes.contains(messageClass),
messageClass.name.endsWith('Keep'));
messageClass.name.endsWith('Keep'),
reason: '$messageClass');
}
final systemTempDir = Directory.systemTemp;
@ -50,8 +51,8 @@ runTestCase(Uri source) async {
printer.writeComponentFile(component);
await sink.close();
ProcessResult result =
Process.runSync(Platform.resolvedExecutable, [file.path]);
final result = Process.runSync(
Platform.resolvedExecutable, ['--enable-asserts', file.path]);
expect(result.exitCode, 0, reason: '${result.stderr}\n${result.stdout}');
} finally {
if (file.existsSync()) {

View file

@ -5,11 +5,12 @@
# Running this script requires having protoc_plugin installed in your path.
rm -rf lib/generated
mkdir lib/generated
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
rm -rf $DIR/lib/generated
mkdir $DIR/lib/generated
# Directory of the script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
GENERATED_DIR=$DIR/lib/generated
protoc --dart_out=$GENERATED_DIR -I$DIR/protos $DIR/protos/*.proto

View file

@ -1,253 +1,345 @@
///
// Generated code. Do not modify.
// source: foo.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
//
// @dart = 2.3
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type
// ignore: UNUSED_SHOWN_NAME
import 'dart:core' show int, bool, double, String, List, Map, override;
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class FooKeep extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('FooKeep')
..a<BarKeep>(
1, 'barKeep', $pb.PbFieldType.OM, BarKeep.getDefault, BarKeep.create)
..a<BarKeep>(
2, 'barDrop', $pb.PbFieldType.OM, BarKeep.getDefault, BarKeep.create)
..m<String, BarKeep>(3, 'mapKeep', 'FooKeep.MapKeepEntry',
$pb.PbFieldType.OS, $pb.PbFieldType.OM, BarKeep.create, null, null)
..m<String, ZopDrop>(4, 'mapDrop', 'FooKeep.MapDropEntry',
$pb.PbFieldType.OS, $pb.PbFieldType.OM, ZopDrop.create, null, null)
..a<int>(5, 'aKeep', $pb.PbFieldType.O3)
..a<HasKeep>(
6, 'hasKeep', $pb.PbFieldType.OM, HasKeep.getDefault, HasKeep.create)
..a<ClearKeep>(7, 'clearKeep', $pb.PbFieldType.OM, ClearKeep.getDefault,
ClearKeep.create)
..hasRequiredFields = false;
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('FooKeep', createEmptyInstance: create)
..aOM<BarKeep>(1, 'barKeep',
protoName: 'barKeep', subBuilder: BarKeep.create)
..aOM<BarKeep>(2, 'barDrop',
protoName: 'barDrop', subBuilder: BarKeep.create)
..m<$core.String, BarKeep>(3, 'mapKeep',
protoName: 'mapKeep',
entryClassName: 'FooKeep.MapKeepEntry',
keyFieldType: $pb.PbFieldType.OS,
valueFieldType: $pb.PbFieldType.OM,
valueCreator: BarKeep.create)
..m<$core.String, ZopDrop>(4, 'mapDrop',
protoName: 'mapDrop',
entryClassName: 'FooKeep.MapDropEntry',
keyFieldType: $pb.PbFieldType.OS,
valueFieldType: $pb.PbFieldType.OM,
valueCreator: ZopDrop.create)
..a<$core.int>(5, 'aKeep', $pb.PbFieldType.O3, protoName: 'aKeep')
..aOM<HasKeep>(6, 'hasKeep',
protoName: 'hasKeep', subBuilder: HasKeep.create)
..aOM<ClearKeep>(7, 'clearKeep',
protoName: 'clearKeep', subBuilder: ClearKeep.create)
..hasRequiredFields = false;
FooKeep() : super();
FooKeep.fromBuffer(List<int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
FooKeep.fromJson(String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
FooKeep clone() => new FooKeep()..mergeFromMessage(this);
FooKeep._() : super();
factory FooKeep() => create();
factory FooKeep.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory FooKeep.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
FooKeep clone() => FooKeep()..mergeFromMessage(this);
FooKeep copyWith(void Function(FooKeep) updates) =>
super.copyWith((message) => updates(message as FooKeep));
$pb.BuilderInfo get info_ => _i;
static FooKeep create() => new FooKeep();
@$core.pragma('dart2js:noInline')
static FooKeep create() => FooKeep._();
FooKeep createEmptyInstance() => create();
static $pb.PbList<FooKeep> createRepeated() => new $pb.PbList<FooKeep>();
static FooKeep getDefault() => _defaultInstance ??= create()..freeze();
static $pb.PbList<FooKeep> createRepeated() => $pb.PbList<FooKeep>();
@$core.pragma('dart2js:noInline')
static FooKeep getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FooKeep>(create);
static FooKeep _defaultInstance;
@$pb.TagNumber(1)
BarKeep get barKeep => $_getN(0);
@$pb.TagNumber(1)
set barKeep(BarKeep v) {
setField(1, v);
}
bool hasBarKeep() => $_has(0);
@$pb.TagNumber(1)
$core.bool hasBarKeep() => $_has(0);
@$pb.TagNumber(1)
void clearBarKeep() => clearField(1);
@$pb.TagNumber(1)
BarKeep ensureBarKeep() => $_ensure(0);
@$pb.TagNumber(2)
BarKeep get barDrop => $_getN(1);
@$pb.TagNumber(2)
set barDrop(BarKeep v) {
setField(2, v);
}
bool hasBarDrop() => $_has(1);
@$pb.TagNumber(2)
$core.bool hasBarDrop() => $_has(1);
@$pb.TagNumber(2)
void clearBarDrop() => clearField(2);
@$pb.TagNumber(2)
BarKeep ensureBarDrop() => $_ensure(1);
Map<String, BarKeep> get mapKeep => $_getMap(2);
@$pb.TagNumber(3)
$core.Map<$core.String, BarKeep> get mapKeep => $_getMap(2);
Map<String, ZopDrop> get mapDrop => $_getMap(3);
@$pb.TagNumber(4)
$core.Map<$core.String, ZopDrop> get mapDrop => $_getMap(3);
int get aKeep => $_get(4, 0);
set aKeep(int v) {
@$pb.TagNumber(5)
$core.int get aKeep => $_getIZ(4);
@$pb.TagNumber(5)
set aKeep($core.int v) {
$_setSignedInt32(4, v);
}
bool hasAKeep() => $_has(4);
@$pb.TagNumber(5)
$core.bool hasAKeep() => $_has(4);
@$pb.TagNumber(5)
void clearAKeep() => clearField(5);
@$pb.TagNumber(6)
HasKeep get hasKeep => $_getN(5);
@$pb.TagNumber(6)
set hasKeep(HasKeep v) {
setField(6, v);
}
bool hasHasKeep() => $_has(5);
@$pb.TagNumber(6)
$core.bool hasHasKeep() => $_has(5);
@$pb.TagNumber(6)
void clearHasKeep() => clearField(6);
@$pb.TagNumber(6)
HasKeep ensureHasKeep() => $_ensure(5);
@$pb.TagNumber(7)
ClearKeep get clearKeep => $_getN(6);
@$pb.TagNumber(7)
set clearKeep(ClearKeep v) {
setField(7, v);
}
bool hasClearKeep() => $_has(6);
@$pb.TagNumber(7)
$core.bool hasClearKeep() => $_has(6);
@$pb.TagNumber(7)
void clearClearKeep() => clearField(7);
@$pb.TagNumber(7)
ClearKeep ensureClearKeep() => $_ensure(6);
}
class BarKeep extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BarKeep')
..a<int>(1, 'aKeep', $pb.PbFieldType.O3)
..a<int>(2, 'bDrop', $pb.PbFieldType.O3)
..hasRequiredFields = false;
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('BarKeep', createEmptyInstance: create)
..a<$core.int>(1, 'aKeep', $pb.PbFieldType.O3, protoName: 'aKeep')
..a<$core.int>(2, 'bDrop', $pb.PbFieldType.O3, protoName: 'bDrop')
..hasRequiredFields = false;
BarKeep() : super();
BarKeep.fromBuffer(List<int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
BarKeep.fromJson(String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
BarKeep clone() => new BarKeep()..mergeFromMessage(this);
BarKeep._() : super();
factory BarKeep() => create();
factory BarKeep.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory BarKeep.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
BarKeep clone() => BarKeep()..mergeFromMessage(this);
BarKeep copyWith(void Function(BarKeep) updates) =>
super.copyWith((message) => updates(message as BarKeep));
$pb.BuilderInfo get info_ => _i;
static BarKeep create() => new BarKeep();
@$core.pragma('dart2js:noInline')
static BarKeep create() => BarKeep._();
BarKeep createEmptyInstance() => create();
static $pb.PbList<BarKeep> createRepeated() => new $pb.PbList<BarKeep>();
static BarKeep getDefault() => _defaultInstance ??= create()..freeze();
static $pb.PbList<BarKeep> createRepeated() => $pb.PbList<BarKeep>();
@$core.pragma('dart2js:noInline')
static BarKeep getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BarKeep>(create);
static BarKeep _defaultInstance;
int get aKeep => $_get(0, 0);
set aKeep(int v) {
@$pb.TagNumber(1)
$core.int get aKeep => $_getIZ(0);
@$pb.TagNumber(1)
set aKeep($core.int v) {
$_setSignedInt32(0, v);
}
bool hasAKeep() => $_has(0);
@$pb.TagNumber(1)
$core.bool hasAKeep() => $_has(0);
@$pb.TagNumber(1)
void clearAKeep() => clearField(1);
int get bDrop => $_get(1, 0);
set bDrop(int v) {
@$pb.TagNumber(2)
$core.int get bDrop => $_getIZ(1);
@$pb.TagNumber(2)
set bDrop($core.int v) {
$_setSignedInt32(1, v);
}
bool hasBDrop() => $_has(1);
@$pb.TagNumber(2)
$core.bool hasBDrop() => $_has(1);
@$pb.TagNumber(2)
void clearBDrop() => clearField(2);
}
class HasKeep extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('HasKeep')
..a<int>(1, 'aDrop', $pb.PbFieldType.O3)
..hasRequiredFields = false;
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('HasKeep', createEmptyInstance: create)
..a<$core.int>(1, 'aDrop', $pb.PbFieldType.O3, protoName: 'aDrop')
..hasRequiredFields = false;
HasKeep() : super();
HasKeep.fromBuffer(List<int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
HasKeep.fromJson(String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
HasKeep clone() => new HasKeep()..mergeFromMessage(this);
HasKeep._() : super();
factory HasKeep() => create();
factory HasKeep.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory HasKeep.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
HasKeep clone() => HasKeep()..mergeFromMessage(this);
HasKeep copyWith(void Function(HasKeep) updates) =>
super.copyWith((message) => updates(message as HasKeep));
$pb.BuilderInfo get info_ => _i;
static HasKeep create() => new HasKeep();
@$core.pragma('dart2js:noInline')
static HasKeep create() => HasKeep._();
HasKeep createEmptyInstance() => create();
static $pb.PbList<HasKeep> createRepeated() => new $pb.PbList<HasKeep>();
static HasKeep getDefault() => _defaultInstance ??= create()..freeze();
static $pb.PbList<HasKeep> createRepeated() => $pb.PbList<HasKeep>();
@$core.pragma('dart2js:noInline')
static HasKeep getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<HasKeep>(create);
static HasKeep _defaultInstance;
int get aDrop => $_get(0, 0);
set aDrop(int v) {
@$pb.TagNumber(1)
$core.int get aDrop => $_getIZ(0);
@$pb.TagNumber(1)
set aDrop($core.int v) {
$_setSignedInt32(0, v);
}
bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
$core.bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
void clearADrop() => clearField(1);
}
class ClearKeep extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ClearKeep')
..a<int>(1, 'aDrop', $pb.PbFieldType.O3)
..hasRequiredFields = false;
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('ClearKeep', createEmptyInstance: create)
..a<$core.int>(1, 'aDrop', $pb.PbFieldType.O3, protoName: 'aDrop')
..hasRequiredFields = false;
ClearKeep() : super();
ClearKeep.fromBuffer(List<int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
ClearKeep.fromJson(String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
ClearKeep clone() => new ClearKeep()..mergeFromMessage(this);
ClearKeep._() : super();
factory ClearKeep() => create();
factory ClearKeep.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory ClearKeep.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
ClearKeep clone() => ClearKeep()..mergeFromMessage(this);
ClearKeep copyWith(void Function(ClearKeep) updates) =>
super.copyWith((message) => updates(message as ClearKeep));
$pb.BuilderInfo get info_ => _i;
static ClearKeep create() => new ClearKeep();
@$core.pragma('dart2js:noInline')
static ClearKeep create() => ClearKeep._();
ClearKeep createEmptyInstance() => create();
static $pb.PbList<ClearKeep> createRepeated() => new $pb.PbList<ClearKeep>();
static ClearKeep getDefault() => _defaultInstance ??= create()..freeze();
static $pb.PbList<ClearKeep> createRepeated() => $pb.PbList<ClearKeep>();
@$core.pragma('dart2js:noInline')
static ClearKeep getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ClearKeep>(create);
static ClearKeep _defaultInstance;
int get aDrop => $_get(0, 0);
set aDrop(int v) {
@$pb.TagNumber(1)
$core.int get aDrop => $_getIZ(0);
@$pb.TagNumber(1)
set aDrop($core.int v) {
$_setSignedInt32(0, v);
}
bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
$core.bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
void clearADrop() => clearField(1);
}
class ZopDrop extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ZopDrop')
..a<int>(1, 'aDrop', $pb.PbFieldType.O3)
..hasRequiredFields = false;
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('ZopDrop', createEmptyInstance: create)
..a<$core.int>(1, 'aDrop', $pb.PbFieldType.O3, protoName: 'aDrop')
..hasRequiredFields = false;
ZopDrop() : super();
ZopDrop.fromBuffer(List<int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
ZopDrop.fromJson(String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
ZopDrop clone() => new ZopDrop()..mergeFromMessage(this);
ZopDrop._() : super();
factory ZopDrop() => create();
factory ZopDrop.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory ZopDrop.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
ZopDrop clone() => ZopDrop()..mergeFromMessage(this);
ZopDrop copyWith(void Function(ZopDrop) updates) =>
super.copyWith((message) => updates(message as ZopDrop));
$pb.BuilderInfo get info_ => _i;
static ZopDrop create() => new ZopDrop();
@$core.pragma('dart2js:noInline')
static ZopDrop create() => ZopDrop._();
ZopDrop createEmptyInstance() => create();
static $pb.PbList<ZopDrop> createRepeated() => new $pb.PbList<ZopDrop>();
static ZopDrop getDefault() => _defaultInstance ??= create()..freeze();
static $pb.PbList<ZopDrop> createRepeated() => $pb.PbList<ZopDrop>();
@$core.pragma('dart2js:noInline')
static ZopDrop getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ZopDrop>(create);
static ZopDrop _defaultInstance;
int get aDrop => $_get(0, 0);
set aDrop(int v) {
@$pb.TagNumber(1)
$core.int get aDrop => $_getIZ(0);
@$pb.TagNumber(1)
set aDrop($core.int v) {
$_setSignedInt32(0, v);
}
bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
$core.bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
void clearADrop() => clearField(1);
}
class MobDrop extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('MobDrop')
..a<int>(1, 'aDrop', $pb.PbFieldType.O3)
..hasRequiredFields = false;
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('MobDrop', createEmptyInstance: create)
..a<$core.int>(1, 'aDrop', $pb.PbFieldType.O3, protoName: 'aDrop')
..hasRequiredFields = false;
MobDrop() : super();
MobDrop.fromBuffer(List<int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
MobDrop.fromJson(String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
MobDrop clone() => new MobDrop()..mergeFromMessage(this);
MobDrop._() : super();
factory MobDrop() => create();
factory MobDrop.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory MobDrop.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
MobDrop clone() => MobDrop()..mergeFromMessage(this);
MobDrop copyWith(void Function(MobDrop) updates) =>
super.copyWith((message) => updates(message as MobDrop));
$pb.BuilderInfo get info_ => _i;
static MobDrop create() => new MobDrop();
@$core.pragma('dart2js:noInline')
static MobDrop create() => MobDrop._();
MobDrop createEmptyInstance() => create();
static $pb.PbList<MobDrop> createRepeated() => new $pb.PbList<MobDrop>();
static MobDrop getDefault() => _defaultInstance ??= create()..freeze();
static $pb.PbList<MobDrop> createRepeated() => $pb.PbList<MobDrop>();
@$core.pragma('dart2js:noInline')
static MobDrop getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<MobDrop>(create);
static MobDrop _defaultInstance;
int get aDrop => $_get(0, 0);
set aDrop(int v) {
@$pb.TagNumber(1)
$core.int get aDrop => $_getIZ(0);
@$pb.TagNumber(1)
set aDrop($core.int v) {
$_setSignedInt32(0, v);
}
bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
$core.bool hasADrop() => $_has(0);
@$pb.TagNumber(1)
void clearADrop() => clearField(1);
}

View file

@ -0,0 +1,80 @@
///
// Generated code. Do not modify.
// source: name_mangling.proto
//
// @dart = 2.3
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class AKeep extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('AKeep', createEmptyInstance: create)
..hasRequiredFields = false;
AKeep._() : super();
factory AKeep() => create();
factory AKeep.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory AKeep.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
AKeep clone() => AKeep()..mergeFromMessage(this);
AKeep copyWith(void Function(AKeep) updates) =>
super.copyWith((message) => updates(message as AKeep));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static AKeep create() => AKeep._();
AKeep createEmptyInstance() => create();
static $pb.PbList<AKeep> createRepeated() => $pb.PbList<AKeep>();
@$core.pragma('dart2js:noInline')
static AKeep getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<AKeep>(create);
static AKeep _defaultInstance;
}
class NameManglingKeep extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i =
$pb.BuilderInfo('NameManglingKeep', createEmptyInstance: create)
..aOM<AKeep>(10, 'clone', subBuilder: AKeep.create)
..hasRequiredFields = false;
NameManglingKeep._() : super();
factory NameManglingKeep() => create();
factory NameManglingKeep.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory NameManglingKeep.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
NameManglingKeep clone() => NameManglingKeep()..mergeFromMessage(this);
NameManglingKeep copyWith(void Function(NameManglingKeep) updates) =>
super.copyWith((message) => updates(message as NameManglingKeep));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static NameManglingKeep create() => NameManglingKeep._();
NameManglingKeep createEmptyInstance() => create();
static $pb.PbList<NameManglingKeep> createRepeated() =>
$pb.PbList<NameManglingKeep>();
@$core.pragma('dart2js:noInline')
static NameManglingKeep getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<NameManglingKeep>(create);
static NameManglingKeep _defaultInstance;
@$pb.TagNumber(10)
AKeep get clone_10 => $_getN(0);
@$pb.TagNumber(10)
set clone_10(AKeep v) {
setField(10, v);
}
@$pb.TagNumber(10)
$core.bool hasClone_10() => $_has(0);
@$pb.TagNumber(10)
void clearClone_10() => clearField(10);
@$pb.TagNumber(10)
AKeep ensureClone_10() => $_ensure(0);
}

View file

@ -0,0 +1,14 @@
// Copyright (c) 2019, the Dart 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.
import 'package:test/test.dart';
import 'generated/name_mangling.pb.dart';
main() {
NameManglingKeep n = NameManglingKeep.fromBuffer([]);
if (n.hasClone_10()) {
print("Has clone field");
}
}

View file

@ -34,8 +34,3 @@ message ZopDrop {
message MobDrop {
int32 aDrop = 1;
}
message A {
B unused = 1;
C used = 2;
}

View file

@ -0,0 +1,10 @@
syntax = "proto3";
message AKeep {}
message NameManglingKeep {
// the name `clone` is mangled by the protoc_plugin to not conflict with
// `GeneratedMessage.clone`.
// Still we should be able to detect usages of this field.
AKeep clone = 10;
}