From 539c10b4d147a36c11064e0931b8cee0e3632e3e Mon Sep 17 00:00:00 2001 From: Sigurd Meldgaard Date: Thu, 24 Oct 2019 06:48:23 +0000 Subject: [PATCH] [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 Reviewed-by: Martin Kustermann --- DEPS | 6 +- .../transformer.dart | 87 +++-- .../treeshaker_test.dart | 7 +- .../compile_protos.sh | 7 +- .../lib/generated/foo.pb.dart | 348 +++++++++++------- .../lib/generated/name_mangling.pb.dart | 80 ++++ .../lib/name_mangling_test.dart | 14 + .../protos/foo.proto | 5 - .../protos/name_mangling.proto | 10 + 9 files changed, 399 insertions(+), 165 deletions(-) create mode 100644 pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/name_mangling.pb.dart create mode 100644 pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/name_mangling_test.dart create mode 100644 pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/name_mangling.proto diff --git a/DEPS b/DEPS index 543745e527f..2a7474080bd 100644 --- a/DEPS +++ b/DEPS @@ -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": diff --git a/pkg/vm/lib/transformations/protobuf_aware_treeshaker/transformer.dart b/pkg/vm/lib/transformations/protobuf_aware_treeshaker/transformer.dart index 7da31945ae5..b00cca1a728 100644 --- a/pkg/vm/lib/transformations/protobuf_aware_treeshaker/transformer.dart +++ b/pkg/vm/lib/transformations/protobuf_aware_treeshaker/transformer.dart @@ -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 { + 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 { // https://github.com/dart-lang/protobuf/blob/master/protoc_plugin/lib/protobuf_field.dart. static final fieldAddingMethods = Set.from(const [ '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(); + final usedTagNumbers = Set(); final dynamicNames = Set(); final CoreTypes coreTypes; final TransformationInfo info; final Member addMethod; - _UnusedFieldMetadataPruner(this.builderInfoClass, this.addMethod, - Set dynamicSelectors, this.coreTypes, this.info) { + _UnusedFieldMetadataPruner(this.tagNumberClass, this.builderInfoClass, + this.addMethod, Set 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 { 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}(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"); } diff --git a/pkg/vm/test/transformations/protobuf_aware_treeshaker/treeshaker_test.dart b/pkg/vm/test/transformations/protobuf_aware_treeshaker/treeshaker_test.dart index 7734f54d3ea..2b2397ac6cb 100644 --- a/pkg/vm/test/transformations/protobuf_aware_treeshaker/treeshaker_test.dart +++ b/pkg/vm/test/transformations/protobuf_aware_treeshaker/treeshaker_test.dart @@ -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()) { diff --git a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/compile_protos.sh b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/compile_protos.sh index b4793eec240..8031891c8b7 100755 --- a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/compile_protos.sh +++ b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/compile_protos.sh @@ -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 diff --git a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/foo.pb.dart b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/foo.pb.dart index 406377357da..cab78838e29 100644 --- a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/foo.pb.dart +++ b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/foo.pb.dart @@ -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( - 1, 'barKeep', $pb.PbFieldType.OM, BarKeep.getDefault, BarKeep.create) - ..a( - 2, 'barDrop', $pb.PbFieldType.OM, BarKeep.getDefault, BarKeep.create) - ..m(3, 'mapKeep', 'FooKeep.MapKeepEntry', - $pb.PbFieldType.OS, $pb.PbFieldType.OM, BarKeep.create, null, null) - ..m(4, 'mapDrop', 'FooKeep.MapDropEntry', - $pb.PbFieldType.OS, $pb.PbFieldType.OM, ZopDrop.create, null, null) - ..a(5, 'aKeep', $pb.PbFieldType.O3) - ..a( - 6, 'hasKeep', $pb.PbFieldType.OM, HasKeep.getDefault, HasKeep.create) - ..a(7, 'clearKeep', $pb.PbFieldType.OM, ClearKeep.getDefault, - ClearKeep.create) - ..hasRequiredFields = false; + static final $pb.BuilderInfo _i = + $pb.BuilderInfo('FooKeep', createEmptyInstance: create) + ..aOM(1, 'barKeep', + protoName: 'barKeep', subBuilder: BarKeep.create) + ..aOM(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(6, 'hasKeep', + protoName: 'hasKeep', subBuilder: HasKeep.create) + ..aOM(7, 'clearKeep', + protoName: 'clearKeep', subBuilder: ClearKeep.create) + ..hasRequiredFields = false; - FooKeep() : super(); - FooKeep.fromBuffer(List 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 createRepeated() => new $pb.PbList(); - static FooKeep getDefault() => _defaultInstance ??= create()..freeze(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static FooKeep getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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 get mapKeep => $_getMap(2); + @$pb.TagNumber(3) + $core.Map<$core.String, BarKeep> get mapKeep => $_getMap(2); - Map 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(1, 'aKeep', $pb.PbFieldType.O3) - ..a(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 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 createRepeated() => new $pb.PbList(); - static BarKeep getDefault() => _defaultInstance ??= create()..freeze(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static BarKeep getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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(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 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 createRepeated() => new $pb.PbList(); - static HasKeep getDefault() => _defaultInstance ??= create()..freeze(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static HasKeep getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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(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 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 createRepeated() => new $pb.PbList(); - static ClearKeep getDefault() => _defaultInstance ??= create()..freeze(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ClearKeep getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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(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 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 createRepeated() => new $pb.PbList(); - static ZopDrop getDefault() => _defaultInstance ??= create()..freeze(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ZopDrop getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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(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 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 createRepeated() => new $pb.PbList(); - static MobDrop getDefault() => _defaultInstance ??= create()..freeze(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static MobDrop getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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); } diff --git a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/name_mangling.pb.dart b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/name_mangling.pb.dart new file mode 100644 index 00000000000..bc76b278381 --- /dev/null +++ b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/generated/name_mangling.pb.dart @@ -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 createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static AKeep getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static AKeep _defaultInstance; +} + +class NameManglingKeep extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = + $pb.BuilderInfo('NameManglingKeep', createEmptyInstance: create) + ..aOM(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 createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static NameManglingKeep getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(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); +} diff --git a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/name_mangling_test.dart b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/name_mangling_test.dart new file mode 100644 index 00000000000..b52c5dcdaca --- /dev/null +++ b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/lib/name_mangling_test.dart @@ -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"); + } +} diff --git a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/foo.proto b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/foo.proto index 0a144338284..1f1087249aa 100644 --- a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/foo.proto +++ b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/foo.proto @@ -34,8 +34,3 @@ message ZopDrop { message MobDrop { int32 aDrop = 1; } - -message A { - B unused = 1; - C used = 2; -} \ No newline at end of file diff --git a/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/name_mangling.proto b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/name_mangling.proto new file mode 100644 index 00000000000..f25b2f48fd2 --- /dev/null +++ b/pkg/vm/testcases/transformations/protobuf_aware_treeshaker/protos/name_mangling.proto @@ -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; +} \ No newline at end of file