From f2f1e6e01811988020762e38fc6379a5510e9c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 09:53:55 +0100 Subject: [PATCH 01/16] Update pre-generated protos --- .../lib/src/gen/dart_options.pb.dart | 2 +- .../lib/src/gen/google/api/client.pb.dart | 21 +- .../lib/src/gen/google/api/http.pb.dart | 17 +- .../lib/src/gen/google/api/routing.pb.dart | 3 +- .../google/protobuf/compiler/plugin.pb.dart | 22 +- .../gen/google/protobuf/descriptor.pb.dart | 280 +++++++----------- .../src/gen/google/protobuf/duration.pb.dart | 2 +- .../google/protobuf/compiler/plugin.proto | 4 +- .../protos/google/protobuf/descriptor.proto | 6 +- 9 files changed, 139 insertions(+), 218 deletions(-) diff --git a/protoc_plugin/lib/src/gen/dart_options.pb.dart b/protoc_plugin/lib/src/gen/dart_options.pb.dart index b92dcb35..06435847 100644 --- a/protoc_plugin/lib/src/gen/dart_options.pb.dart +++ b/protoc_plugin/lib/src/gen/dart_options.pb.dart @@ -125,7 +125,7 @@ class Imports extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'Imports', package: const $pb.PackageName(_omitMessageNames ? '' : 'dart_options'), createEmptyInstance: create) - ..pc(1, _omitFieldNames ? '' : 'mixins', $pb.PbFieldType.PM, + ..pPM(1, _omitFieldNames ? '' : 'mixins', subBuilder: DartMixin.create) ..hasRequiredFields = false; diff --git a/protoc_plugin/lib/src/gen/google/api/client.pb.dart b/protoc_plugin/lib/src/gen/google/api/client.pb.dart index fdf9cbe7..3cc4ee4b 100644 --- a/protoc_plugin/lib/src/gen/google/api/client.pb.dart +++ b/protoc_plugin/lib/src/gen/google/api/client.pb.dart @@ -162,10 +162,7 @@ class ClientLibrarySettings extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.api'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'version') - ..e<$1.LaunchStage>( - 2, _omitFieldNames ? '' : 'launchStage', $pb.PbFieldType.OE, - defaultOrMaker: $1.LaunchStage.LAUNCH_STAGE_UNSPECIFIED, - valueOf: $1.LaunchStage.valueOf, + ..aE<$1.LaunchStage>(2, _omitFieldNames ? '' : 'launchStage', enumValues: $1.LaunchStage.values) ..aOB(3, _omitFieldNames ? '' : 'restNumericEnums') ..aOM(21, _omitFieldNames ? '' : 'javaSettings', @@ -386,8 +383,7 @@ class Publishing extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'Publishing', package: const $pb.PackageName(_omitMessageNames ? '' : 'google.api'), createEmptyInstance: create) - ..pc( - 2, _omitFieldNames ? '' : 'methodSettings', $pb.PbFieldType.PM, + ..pPM(2, _omitFieldNames ? '' : 'methodSettings', subBuilder: MethodSettings.create) ..aOS(101, _omitFieldNames ? '' : 'newIssueUri') ..aOS(102, _omitFieldNames ? '' : 'documentationUri') @@ -395,14 +391,9 @@ class Publishing extends $pb.GeneratedMessage { ..aOS(104, _omitFieldNames ? '' : 'githubLabel') ..pPS(105, _omitFieldNames ? '' : 'codeownerGithubTeams') ..aOS(106, _omitFieldNames ? '' : 'docTagPrefix') - ..e( - 107, _omitFieldNames ? '' : 'organization', $pb.PbFieldType.OE, - defaultOrMaker: - ClientLibraryOrganization.CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED, - valueOf: ClientLibraryOrganization.valueOf, + ..aE(107, _omitFieldNames ? '' : 'organization', enumValues: ClientLibraryOrganization.values) - ..pc( - 109, _omitFieldNames ? '' : 'librarySettings', $pb.PbFieldType.PM, + ..pPM(109, _omitFieldNames ? '' : 'librarySettings', subBuilder: ClientLibrarySettings.create) ..aOS(110, _omitFieldNames ? '' : 'protoReferenceDocumentationUri') ..aOS(111, _omitFieldNames ? '' : 'restReferenceDocumentationUri') @@ -1310,8 +1301,8 @@ class MethodSettings_LongRunning extends $pb.GeneratedMessage { createEmptyInstance: create) ..aOM<$0.Duration>(1, _omitFieldNames ? '' : 'initialPollDelay', subBuilder: $0.Duration.create) - ..a<$core.double>( - 2, _omitFieldNames ? '' : 'pollDelayMultiplier', $pb.PbFieldType.OF) + ..aD(2, _omitFieldNames ? '' : 'pollDelayMultiplier', + fieldType: $pb.PbFieldType.OF) ..aOM<$0.Duration>(3, _omitFieldNames ? '' : 'maxPollDelay', subBuilder: $0.Duration.create) ..aOM<$0.Duration>(4, _omitFieldNames ? '' : 'totalPollTimeout', diff --git a/protoc_plugin/lib/src/gen/google/api/http.pb.dart b/protoc_plugin/lib/src/gen/google/api/http.pb.dart index 018fa1a0..a4964041 100644 --- a/protoc_plugin/lib/src/gen/google/api/http.pb.dart +++ b/protoc_plugin/lib/src/gen/google/api/http.pb.dart @@ -44,7 +44,7 @@ class Http extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'Http', package: const $pb.PackageName(_omitMessageNames ? '' : 'google.api'), createEmptyInstance: create) - ..pc(1, _omitFieldNames ? '' : 'rules', $pb.PbFieldType.PM, + ..pPM(1, _omitFieldNames ? '' : 'rules', subBuilder: HttpRule.create) ..aOB(2, _omitFieldNames ? '' : 'fullyDecodeReservedExpansion') ..hasRequiredFields = false; @@ -416,8 +416,7 @@ class HttpRule extends $pb.GeneratedMessage { ..aOS(7, _omitFieldNames ? '' : 'body') ..aOM(8, _omitFieldNames ? '' : 'custom', subBuilder: CustomHttpPattern.create) - ..pc( - 11, _omitFieldNames ? '' : 'additionalBindings', $pb.PbFieldType.PM, + ..pPM(11, _omitFieldNames ? '' : 'additionalBindings', subBuilder: HttpRule.create) ..aOS(12, _omitFieldNames ? '' : 'responseBody') ..hasRequiredFields = false; @@ -441,7 +440,19 @@ class HttpRule extends $pb.GeneratedMessage { _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static HttpRule? _defaultInstance; + @$pb.TagNumber(2) + @$pb.TagNumber(3) + @$pb.TagNumber(4) + @$pb.TagNumber(5) + @$pb.TagNumber(6) + @$pb.TagNumber(8) HttpRule_Pattern whichPattern() => _HttpRule_PatternByTag[$_whichOneof(0)]!; + @$pb.TagNumber(2) + @$pb.TagNumber(3) + @$pb.TagNumber(4) + @$pb.TagNumber(5) + @$pb.TagNumber(6) + @$pb.TagNumber(8) void clearPattern() => $_clearField($_whichOneof(0)); /// Selects a method to which this rule applies. diff --git a/protoc_plugin/lib/src/gen/google/api/routing.pb.dart b/protoc_plugin/lib/src/gen/google/api/routing.pb.dart index 528ac007..28bb7421 100644 --- a/protoc_plugin/lib/src/gen/google/api/routing.pb.dart +++ b/protoc_plugin/lib/src/gen/google/api/routing.pb.dart @@ -398,8 +398,7 @@ class RoutingRule extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'RoutingRule', package: const $pb.PackageName(_omitMessageNames ? '' : 'google.api'), createEmptyInstance: create) - ..pc( - 2, _omitFieldNames ? '' : 'routingParameters', $pb.PbFieldType.PM, + ..pPM(2, _omitFieldNames ? '' : 'routingParameters', subBuilder: RoutingParameter.create) ..hasRequiredFields = false; diff --git a/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart b/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart index bbdcac1c..3bee3157 100644 --- a/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart +++ b/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart @@ -51,9 +51,9 @@ class Version extends $pb.GeneratedMessage { package: const $pb.PackageName( _omitMessageNames ? '' : 'google.protobuf.compiler'), createEmptyInstance: create) - ..a<$core.int>(1, _omitFieldNames ? '' : 'major', $pb.PbFieldType.O3) - ..a<$core.int>(2, _omitFieldNames ? '' : 'minor', $pb.PbFieldType.O3) - ..a<$core.int>(3, _omitFieldNames ? '' : 'patch', $pb.PbFieldType.O3) + ..aI(1, _omitFieldNames ? '' : 'major') + ..aI(2, _omitFieldNames ? '' : 'minor') + ..aI(3, _omitFieldNames ? '' : 'patch') ..aOS(4, _omitFieldNames ? '' : 'suffix') ..hasRequiredFields = false; @@ -152,11 +152,10 @@ class CodeGeneratorRequest extends $pb.GeneratedMessage { ..aOS(2, _omitFieldNames ? '' : 'parameter') ..aOM(3, _omitFieldNames ? '' : 'compilerVersion', subBuilder: Version.create) - ..pc<$0.FileDescriptorProto>( - 15, _omitFieldNames ? '' : 'protoFile', $pb.PbFieldType.PM, + ..pPM<$0.FileDescriptorProto>(15, _omitFieldNames ? '' : 'protoFile', subBuilder: $0.FileDescriptorProto.create) - ..pc<$0.FileDescriptorProto>( - 17, _omitFieldNames ? '' : 'sourceFileDescriptors', $pb.PbFieldType.PM, + ..pPM<$0.FileDescriptorProto>( + 17, _omitFieldNames ? '' : 'sourceFileDescriptors', subBuilder: $0.FileDescriptorProto.create); @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -424,12 +423,9 @@ class CodeGeneratorResponse extends $pb.GeneratedMessage { ..a<$fixnum.Int64>( 2, _omitFieldNames ? '' : 'supportedFeatures', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) - ..a<$core.int>( - 3, _omitFieldNames ? '' : 'minimumEdition', $pb.PbFieldType.O3) - ..a<$core.int>( - 4, _omitFieldNames ? '' : 'maximumEdition', $pb.PbFieldType.O3) - ..pc( - 15, _omitFieldNames ? '' : 'file', $pb.PbFieldType.PM, + ..aI(3, _omitFieldNames ? '' : 'minimumEdition') + ..aI(4, _omitFieldNames ? '' : 'maximumEdition') + ..pPM(15, _omitFieldNames ? '' : 'file', subBuilder: CodeGeneratorResponse_File.create) ..hasRequiredFields = false; diff --git a/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart b/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart index 4e051934..a4959473 100644 --- a/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart +++ b/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart @@ -46,8 +46,7 @@ class FileDescriptorSet extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..pc( - 1, _omitFieldNames ? '' : 'file', $pb.PbFieldType.PM, + ..pPM(1, _omitFieldNames ? '' : 'file', subBuilder: FileDescriptorProto.create) ..hasExtensions = true; @@ -131,17 +130,13 @@ class FileDescriptorProto extends $pb.GeneratedMessage { ..aOS(1, _omitFieldNames ? '' : 'name') ..aOS(2, _omitFieldNames ? '' : 'package') ..pPS(3, _omitFieldNames ? '' : 'dependency') - ..pc( - 4, _omitFieldNames ? '' : 'messageType', $pb.PbFieldType.PM, + ..pPM(4, _omitFieldNames ? '' : 'messageType', subBuilder: DescriptorProto.create) - ..pc( - 5, _omitFieldNames ? '' : 'enumType', $pb.PbFieldType.PM, + ..pPM(5, _omitFieldNames ? '' : 'enumType', subBuilder: EnumDescriptorProto.create) - ..pc( - 6, _omitFieldNames ? '' : 'service', $pb.PbFieldType.PM, + ..pPM(6, _omitFieldNames ? '' : 'service', subBuilder: ServiceDescriptorProto.create) - ..pc( - 7, _omitFieldNames ? '' : 'extension', $pb.PbFieldType.PM, + ..pPM(7, _omitFieldNames ? '' : 'extension', subBuilder: FieldDescriptorProto.create) ..aOM(8, _omitFieldNames ? '' : 'options', subBuilder: FileOptions.create) @@ -152,9 +147,7 @@ class FileDescriptorProto extends $pb.GeneratedMessage { ..p<$core.int>( 11, _omitFieldNames ? '' : 'weakDependency', $pb.PbFieldType.P3) ..aOS(12, _omitFieldNames ? '' : 'syntax') - ..e(14, _omitFieldNames ? '' : 'edition', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(14, _omitFieldNames ? '' : 'edition', enumValues: Edition.values) ..pPS(15, _omitFieldNames ? '' : 'optionDependency'); @@ -311,8 +304,8 @@ class DescriptorProto_ExtensionRange extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..a<$core.int>(1, _omitFieldNames ? '' : 'start', $pb.PbFieldType.O3) - ..a<$core.int>(2, _omitFieldNames ? '' : 'end', $pb.PbFieldType.O3) + ..aI(1, _omitFieldNames ? '' : 'start') + ..aI(2, _omitFieldNames ? '' : 'end') ..aOM(3, _omitFieldNames ? '' : 'options', subBuilder: ExtensionRangeOptions.create); @@ -398,8 +391,8 @@ class DescriptorProto_ReservedRange extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..a<$core.int>(1, _omitFieldNames ? '' : 'start', $pb.PbFieldType.O3) - ..a<$core.int>(2, _omitFieldNames ? '' : 'end', $pb.PbFieldType.O3) + ..aI(1, _omitFieldNames ? '' : 'start') + ..aI(2, _omitFieldNames ? '' : 'end') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -490,34 +483,26 @@ class DescriptorProto extends $pb.GeneratedMessage { const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'name') - ..pc( - 2, _omitFieldNames ? '' : 'field', $pb.PbFieldType.PM, + ..pPM(2, _omitFieldNames ? '' : 'field', subBuilder: FieldDescriptorProto.create) - ..pc( - 3, _omitFieldNames ? '' : 'nestedType', $pb.PbFieldType.PM, + ..pPM(3, _omitFieldNames ? '' : 'nestedType', subBuilder: DescriptorProto.create) - ..pc( - 4, _omitFieldNames ? '' : 'enumType', $pb.PbFieldType.PM, + ..pPM(4, _omitFieldNames ? '' : 'enumType', subBuilder: EnumDescriptorProto.create) - ..pc( - 5, _omitFieldNames ? '' : 'extensionRange', $pb.PbFieldType.PM, + ..pPM( + 5, _omitFieldNames ? '' : 'extensionRange', subBuilder: DescriptorProto_ExtensionRange.create) - ..pc( - 6, _omitFieldNames ? '' : 'extension', $pb.PbFieldType.PM, + ..pPM(6, _omitFieldNames ? '' : 'extension', subBuilder: FieldDescriptorProto.create) ..aOM(7, _omitFieldNames ? '' : 'options', subBuilder: MessageOptions.create) - ..pc( - 8, _omitFieldNames ? '' : 'oneofDecl', $pb.PbFieldType.PM, + ..pPM(8, _omitFieldNames ? '' : 'oneofDecl', subBuilder: OneofDescriptorProto.create) - ..pc( - 9, _omitFieldNames ? '' : 'reservedRange', $pb.PbFieldType.PM, + ..pPM( + 9, _omitFieldNames ? '' : 'reservedRange', subBuilder: DescriptorProto_ReservedRange.create) ..pPS(10, _omitFieldNames ? '' : 'reservedName') - ..e( - 11, _omitFieldNames ? '' : 'visibility', $pb.PbFieldType.OE, - defaultOrMaker: SymbolVisibility.VISIBILITY_UNSET, - valueOf: SymbolVisibility.valueOf, + ..aE(11, _omitFieldNames ? '' : 'visibility', enumValues: SymbolVisibility.values); @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -630,7 +615,7 @@ class ExtensionRangeOptions_Declaration extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..a<$core.int>(1, _omitFieldNames ? '' : 'number', $pb.PbFieldType.O3) + ..aI(1, _omitFieldNames ? '' : 'number') ..aOS(2, _omitFieldNames ? '' : 'fullName') ..aOS(3, _omitFieldNames ? '' : 'type') ..aOB(5, _omitFieldNames ? '' : 'reserved') @@ -749,18 +734,17 @@ class ExtensionRangeOptions extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..pc( - 2, _omitFieldNames ? '' : 'declaration', $pb.PbFieldType.PM, + ..pPM( + 2, _omitFieldNames ? '' : 'declaration', subBuilder: ExtensionRangeOptions_Declaration.create) - ..e( - 3, _omitFieldNames ? '' : 'verification', $pb.PbFieldType.OE, + ..aE( + 3, _omitFieldNames ? '' : 'verification', defaultOrMaker: ExtensionRangeOptions_VerificationState.UNVERIFIED, - valueOf: ExtensionRangeOptions_VerificationState.valueOf, enumValues: ExtensionRangeOptions_VerificationState.values) ..aOM(50, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -868,22 +852,16 @@ class FieldDescriptorProto extends $pb.GeneratedMessage { createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'name') ..aOS(2, _omitFieldNames ? '' : 'extendee') - ..a<$core.int>(3, _omitFieldNames ? '' : 'number', $pb.PbFieldType.O3) - ..e( - 4, _omitFieldNames ? '' : 'label', $pb.PbFieldType.OE, - defaultOrMaker: FieldDescriptorProto_Label.LABEL_OPTIONAL, - valueOf: FieldDescriptorProto_Label.valueOf, + ..aI(3, _omitFieldNames ? '' : 'number') + ..aE(4, _omitFieldNames ? '' : 'label', enumValues: FieldDescriptorProto_Label.values) - ..e( - 5, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, - defaultOrMaker: FieldDescriptorProto_Type.TYPE_DOUBLE, - valueOf: FieldDescriptorProto_Type.valueOf, + ..aE(5, _omitFieldNames ? '' : 'type', enumValues: FieldDescriptorProto_Type.values) ..aOS(6, _omitFieldNames ? '' : 'typeName') ..aOS(7, _omitFieldNames ? '' : 'defaultValue') ..aOM(8, _omitFieldNames ? '' : 'options', subBuilder: FieldOptions.create) - ..a<$core.int>(9, _omitFieldNames ? '' : 'oneofIndex', $pb.PbFieldType.O3) + ..aI(9, _omitFieldNames ? '' : 'oneofIndex') ..aOS(10, _omitFieldNames ? '' : 'jsonName') ..aOB(17, _omitFieldNames ? '' : 'proto3Optional'); @@ -1154,8 +1132,8 @@ class EnumDescriptorProto_EnumReservedRange extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..a<$core.int>(1, _omitFieldNames ? '' : 'start', $pb.PbFieldType.O3) - ..a<$core.int>(2, _omitFieldNames ? '' : 'end', $pb.PbFieldType.O3) + ..aI(1, _omitFieldNames ? '' : 'start') + ..aI(2, _omitFieldNames ? '' : 'end') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -1237,19 +1215,15 @@ class EnumDescriptorProto extends $pb.GeneratedMessage { const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'name') - ..pc( - 2, _omitFieldNames ? '' : 'value', $pb.PbFieldType.PM, + ..pPM(2, _omitFieldNames ? '' : 'value', subBuilder: EnumValueDescriptorProto.create) ..aOM(3, _omitFieldNames ? '' : 'options', subBuilder: EnumOptions.create) - ..pc( - 4, _omitFieldNames ? '' : 'reservedRange', $pb.PbFieldType.PM, + ..pPM( + 4, _omitFieldNames ? '' : 'reservedRange', subBuilder: EnumDescriptorProto_EnumReservedRange.create) ..pPS(5, _omitFieldNames ? '' : 'reservedName') - ..e( - 6, _omitFieldNames ? '' : 'visibility', $pb.PbFieldType.OE, - defaultOrMaker: SymbolVisibility.VISIBILITY_UNSET, - valueOf: SymbolVisibility.valueOf, + ..aE(6, _omitFieldNames ? '' : 'visibility', enumValues: SymbolVisibility.values); @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -1348,7 +1322,7 @@ class EnumValueDescriptorProto extends $pb.GeneratedMessage { const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'name') - ..a<$core.int>(2, _omitFieldNames ? '' : 'number', $pb.PbFieldType.O3) + ..aI(2, _omitFieldNames ? '' : 'number') ..aOM(3, _omitFieldNames ? '' : 'options', subBuilder: EnumValueOptions.create); @@ -1433,8 +1407,7 @@ class ServiceDescriptorProto extends $pb.GeneratedMessage { const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'name') - ..pc( - 2, _omitFieldNames ? '' : 'method', $pb.PbFieldType.PM, + ..pPM(2, _omitFieldNames ? '' : 'method', subBuilder: MethodDescriptorProto.create) ..aOM(3, _omitFieldNames ? '' : 'options', subBuilder: ServiceOptions.create); @@ -1682,10 +1655,8 @@ class FileOptions extends $pb.GeneratedMessage { createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'javaPackage') ..aOS(8, _omitFieldNames ? '' : 'javaOuterClassname') - ..e( - 9, _omitFieldNames ? '' : 'optimizeFor', $pb.PbFieldType.OE, + ..aE(9, _omitFieldNames ? '' : 'optimizeFor', defaultOrMaker: FileOptions_OptimizeMode.SPEED, - valueOf: FileOptions_OptimizeMode.valueOf, enumValues: FileOptions_OptimizeMode.values) ..aOB(10, _omitFieldNames ? '' : 'javaMultipleFiles') ..aOS(11, _omitFieldNames ? '' : 'goPackage') @@ -1707,8 +1678,8 @@ class FileOptions extends $pb.GeneratedMessage { ..aOS(45, _omitFieldNames ? '' : 'rubyPackage') ..aOM(50, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -2041,8 +2012,8 @@ class MessageOptions extends $pb.GeneratedMessage { ..aOB(11, _omitFieldNames ? '' : 'deprecatedLegacyJsonFieldConflicts') ..aOM(12, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -2219,9 +2190,7 @@ class FieldOptions_EditionDefault extends $pb.GeneratedMessage { const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) ..aOS(2, _omitFieldNames ? '' : 'value') - ..e(3, _omitFieldNames ? '' : 'edition', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(3, _omitFieldNames ? '' : 'edition', enumValues: Edition.values) ..hasRequiredFields = false; @@ -2299,20 +2268,12 @@ class FieldOptions_FeatureSupport extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..e( - 1, _omitFieldNames ? '' : 'editionIntroduced', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(1, _omitFieldNames ? '' : 'editionIntroduced', enumValues: Edition.values) - ..e( - 2, _omitFieldNames ? '' : 'editionDeprecated', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(2, _omitFieldNames ? '' : 'editionDeprecated', enumValues: Edition.values) ..aOS(3, _omitFieldNames ? '' : 'deprecationWarning') - ..e(4, _omitFieldNames ? '' : 'editionRemoved', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(4, _omitFieldNames ? '' : 'editionRemoved', enumValues: Edition.values) ..hasRequiredFields = false; @@ -2394,7 +2355,7 @@ class FieldOptions extends $pb.GeneratedMessage { $core.bool? deprecated, $core.bool? lazy, FieldOptions_JSType? jstype, - $core.bool? weak, + @$core.Deprecated('This field is deprecated.') $core.bool? weak, $core.bool? unverifiedLazy, $core.bool? debugRedact, FieldOptions_OptionRetention? retention, @@ -2437,42 +2398,32 @@ class FieldOptions extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..e( - 1, _omitFieldNames ? '' : 'ctype', $pb.PbFieldType.OE, + ..aE(1, _omitFieldNames ? '' : 'ctype', defaultOrMaker: FieldOptions_CType.STRING, - valueOf: FieldOptions_CType.valueOf, enumValues: FieldOptions_CType.values) ..aOB(2, _omitFieldNames ? '' : 'packed') ..aOB(3, _omitFieldNames ? '' : 'deprecated') ..aOB(5, _omitFieldNames ? '' : 'lazy') - ..e( - 6, _omitFieldNames ? '' : 'jstype', $pb.PbFieldType.OE, + ..aE(6, _omitFieldNames ? '' : 'jstype', defaultOrMaker: FieldOptions_JSType.JS_NORMAL, - valueOf: FieldOptions_JSType.valueOf, enumValues: FieldOptions_JSType.values) ..aOB(10, _omitFieldNames ? '' : 'weak') ..aOB(15, _omitFieldNames ? '' : 'unverifiedLazy') ..aOB(16, _omitFieldNames ? '' : 'debugRedact') - ..e( - 17, _omitFieldNames ? '' : 'retention', $pb.PbFieldType.OE, - defaultOrMaker: FieldOptions_OptionRetention.RETENTION_UNKNOWN, - valueOf: FieldOptions_OptionRetention.valueOf, + ..aE(17, _omitFieldNames ? '' : 'retention', enumValues: FieldOptions_OptionRetention.values) - ..pc( - 19, _omitFieldNames ? '' : 'targets', $pb.PbFieldType.PE, - valueOf: FieldOptions_OptionTargetType.valueOf, - enumValues: FieldOptions_OptionTargetType.values, - defaultEnumValue: FieldOptions_OptionTargetType.TARGET_TYPE_UNKNOWN) - ..pc( - 20, _omitFieldNames ? '' : 'editionDefaults', $pb.PbFieldType.PM, + ..pPE(19, _omitFieldNames ? '' : 'targets', + enumValues: FieldOptions_OptionTargetType.values) + ..pPM( + 20, _omitFieldNames ? '' : 'editionDefaults', subBuilder: FieldOptions_EditionDefault.create) ..aOM(21, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) ..aOM( 22, _omitFieldNames ? '' : 'featureSupport', subBuilder: FieldOptions_FeatureSupport.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -2593,13 +2544,18 @@ class FieldOptions extends $pb.GeneratedMessage { @$pb.TagNumber(6) void clearJstype() => $_clearField(6); + /// DEPRECATED. DO NOT USE! /// For Google-internal migration only. Do not use. + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(10) $core.bool get weak => $_getBF(5); + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(10) set weak($core.bool value) => $_setBool(5, value); + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(10) $core.bool hasWeak() => $_has(5); + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(10) void clearWeak() => $_clearField(10); @@ -2701,8 +2657,8 @@ class OneofOptions extends $pb.GeneratedMessage { createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -2787,8 +2743,8 @@ class EnumOptions extends $pb.GeneratedMessage { ..aOB(6, _omitFieldNames ? '' : 'deprecatedLegacyJsonFieldConflicts') ..aOM(7, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -2915,8 +2871,8 @@ class EnumValueOptions extends $pb.GeneratedMessage { ..aOM( 4, _omitFieldNames ? '' : 'featureSupport', subBuilder: FieldOptions_FeatureSupport.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -3029,8 +2985,8 @@ class ServiceOptions extends $pb.GeneratedMessage { ..aOB(33, _omitFieldNames ? '' : 'deprecated') ..aOM(34, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -3119,15 +3075,14 @@ class MethodOptions extends $pb.GeneratedMessage { const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) ..aOB(33, _omitFieldNames ? '' : 'deprecated') - ..e( - 34, _omitFieldNames ? '' : 'idempotencyLevel', $pb.PbFieldType.OE, + ..aE( + 34, _omitFieldNames ? '' : 'idempotencyLevel', defaultOrMaker: MethodOptions_IdempotencyLevel.IDEMPOTENCY_UNKNOWN, - valueOf: MethodOptions_IdempotencyLevel.valueOf, enumValues: MethodOptions_IdempotencyLevel.values) ..aOM(35, _omitFieldNames ? '' : 'features', subBuilder: FeatureSet.create) - ..pc( - 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, + ..pPM( + 999, _omitFieldNames ? '' : 'uninterpretedOption', subBuilder: UninterpretedOption.create) ..hasExtensions = true; @@ -3313,16 +3268,14 @@ class UninterpretedOption extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..pc( - 2, _omitFieldNames ? '' : 'name', $pb.PbFieldType.PM, + ..pPM(2, _omitFieldNames ? '' : 'name', subBuilder: UninterpretedOption_NamePart.create) ..aOS(3, _omitFieldNames ? '' : 'identifierValue') ..a<$fixnum.Int64>( 4, _omitFieldNames ? '' : 'positiveIntValue', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aInt64(5, _omitFieldNames ? '' : 'negativeIntValue') - ..a<$core.double>( - 6, _omitFieldNames ? '' : 'doubleValue', $pb.PbFieldType.OD) + ..aD(6, _omitFieldNames ? '' : 'doubleValue') ..a<$core.List<$core.int>>( 7, _omitFieldNames ? '' : 'stringValue', $pb.PbFieldType.OY) ..aOS(8, _omitFieldNames ? '' : 'aggregateValue'); @@ -3499,48 +3452,25 @@ class FeatureSet extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..e( - 1, _omitFieldNames ? '' : 'fieldPresence', $pb.PbFieldType.OE, - defaultOrMaker: FeatureSet_FieldPresence.FIELD_PRESENCE_UNKNOWN, - valueOf: FeatureSet_FieldPresence.valueOf, + ..aE(1, _omitFieldNames ? '' : 'fieldPresence', enumValues: FeatureSet_FieldPresence.values) - ..e( - 2, _omitFieldNames ? '' : 'enumType', $pb.PbFieldType.OE, - defaultOrMaker: FeatureSet_EnumType.ENUM_TYPE_UNKNOWN, - valueOf: FeatureSet_EnumType.valueOf, + ..aE(2, _omitFieldNames ? '' : 'enumType', enumValues: FeatureSet_EnumType.values) - ..e( - 3, _omitFieldNames ? '' : 'repeatedFieldEncoding', $pb.PbFieldType.OE, - defaultOrMaker: - FeatureSet_RepeatedFieldEncoding.REPEATED_FIELD_ENCODING_UNKNOWN, - valueOf: FeatureSet_RepeatedFieldEncoding.valueOf, + ..aE( + 3, _omitFieldNames ? '' : 'repeatedFieldEncoding', enumValues: FeatureSet_RepeatedFieldEncoding.values) - ..e( - 4, _omitFieldNames ? '' : 'utf8Validation', $pb.PbFieldType.OE, - defaultOrMaker: FeatureSet_Utf8Validation.UTF8_VALIDATION_UNKNOWN, - valueOf: FeatureSet_Utf8Validation.valueOf, + ..aE(4, _omitFieldNames ? '' : 'utf8Validation', enumValues: FeatureSet_Utf8Validation.values) - ..e( - 5, _omitFieldNames ? '' : 'messageEncoding', $pb.PbFieldType.OE, - defaultOrMaker: FeatureSet_MessageEncoding.MESSAGE_ENCODING_UNKNOWN, - valueOf: FeatureSet_MessageEncoding.valueOf, + ..aE( + 5, _omitFieldNames ? '' : 'messageEncoding', enumValues: FeatureSet_MessageEncoding.values) - ..e( - 6, _omitFieldNames ? '' : 'jsonFormat', $pb.PbFieldType.OE, - defaultOrMaker: FeatureSet_JsonFormat.JSON_FORMAT_UNKNOWN, - valueOf: FeatureSet_JsonFormat.valueOf, + ..aE(6, _omitFieldNames ? '' : 'jsonFormat', enumValues: FeatureSet_JsonFormat.values) - ..e( - 7, _omitFieldNames ? '' : 'enforceNamingStyle', $pb.PbFieldType.OE, - defaultOrMaker: - FeatureSet_EnforceNamingStyle.ENFORCE_NAMING_STYLE_UNKNOWN, - valueOf: FeatureSet_EnforceNamingStyle.valueOf, + ..aE( + 7, _omitFieldNames ? '' : 'enforceNamingStyle', enumValues: FeatureSet_EnforceNamingStyle.values) - ..e( - 8, _omitFieldNames ? '' : 'defaultSymbolVisibility', $pb.PbFieldType.OE, - defaultOrMaker: FeatureSet_VisibilityFeature_DefaultSymbolVisibility - .DEFAULT_SYMBOL_VISIBILITY_UNKNOWN, - valueOf: FeatureSet_VisibilityFeature_DefaultSymbolVisibility.valueOf, + ..aE( + 8, _omitFieldNames ? '' : 'defaultSymbolVisibility', enumValues: FeatureSet_VisibilityFeature_DefaultSymbolVisibility.values) ..hasExtensions = true; @@ -3675,9 +3605,7 @@ class FeatureSetDefaults_FeatureSetEditionDefault extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..e(3, _omitFieldNames ? '' : 'edition', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(3, _omitFieldNames ? '' : 'edition', enumValues: Edition.values) ..aOM(4, _omitFieldNames ? '' : 'overridableFeatures', subBuilder: FeatureSet.create) @@ -3775,16 +3703,12 @@ class FeatureSetDefaults extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..pc( - 1, _omitFieldNames ? '' : 'defaults', $pb.PbFieldType.PM, + ..pPM( + 1, _omitFieldNames ? '' : 'defaults', subBuilder: FeatureSetDefaults_FeatureSetEditionDefault.create) - ..e(4, _omitFieldNames ? '' : 'minimumEdition', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(4, _omitFieldNames ? '' : 'minimumEdition', enumValues: Edition.values) - ..e(5, _omitFieldNames ? '' : 'maximumEdition', $pb.PbFieldType.OE, - defaultOrMaker: Edition.EDITION_UNKNOWN, - valueOf: Edition.valueOf, + ..aE(5, _omitFieldNames ? '' : 'maximumEdition', enumValues: Edition.values); @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -4024,8 +3948,7 @@ class SourceCodeInfo extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..pc( - 1, _omitFieldNames ? '' : 'location', $pb.PbFieldType.PM, + ..pPM(1, _omitFieldNames ? '' : 'location', subBuilder: SourceCodeInfo_Location.create) ..hasExtensions = true; @@ -4130,12 +4053,10 @@ class GeneratedCodeInfo_Annotation extends $pb.GeneratedMessage { createEmptyInstance: create) ..p<$core.int>(1, _omitFieldNames ? '' : 'path', $pb.PbFieldType.K3) ..aOS(2, _omitFieldNames ? '' : 'sourceFile') - ..a<$core.int>(3, _omitFieldNames ? '' : 'begin', $pb.PbFieldType.O3) - ..a<$core.int>(4, _omitFieldNames ? '' : 'end', $pb.PbFieldType.O3) - ..e( - 5, _omitFieldNames ? '' : 'semantic', $pb.PbFieldType.OE, - defaultOrMaker: GeneratedCodeInfo_Annotation_Semantic.NONE, - valueOf: GeneratedCodeInfo_Annotation_Semantic.valueOf, + ..aI(3, _omitFieldNames ? '' : 'begin') + ..aI(4, _omitFieldNames ? '' : 'end') + ..aE( + 5, _omitFieldNames ? '' : 'semantic', enumValues: GeneratedCodeInfo_Annotation_Semantic.values) ..hasRequiredFields = false; @@ -4238,8 +4159,7 @@ class GeneratedCodeInfo extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create) - ..pc( - 1, _omitFieldNames ? '' : 'annotation', $pb.PbFieldType.PM, + ..pPM(1, _omitFieldNames ? '' : 'annotation', subBuilder: GeneratedCodeInfo_Annotation.create) ..hasRequiredFields = false; diff --git a/protoc_plugin/lib/src/gen/google/protobuf/duration.pb.dart b/protoc_plugin/lib/src/gen/google/protobuf/duration.pb.dart index 343ec9dd..fafadb50 100644 --- a/protoc_plugin/lib/src/gen/google/protobuf/duration.pb.dart +++ b/protoc_plugin/lib/src/gen/google/protobuf/duration.pb.dart @@ -104,7 +104,7 @@ class Duration extends $pb.GeneratedMessage with $mixin.DurationMixin { createEmptyInstance: create, wellKnownType: $mixin.WellKnownType.duration) ..aInt64(1, _omitFieldNames ? '' : 'seconds') - ..a<$core.int>(2, _omitFieldNames ? '' : 'nanos', $pb.PbFieldType.O3) + ..aI(2, _omitFieldNames ? '' : 'nanos') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') diff --git a/protoc_plugin/protos/google/protobuf/compiler/plugin.proto b/protoc_plugin/protos/google/protobuf/compiler/plugin.proto index 033fab23..10d285f8 100644 --- a/protoc_plugin/protos/google/protobuf/compiler/plugin.proto +++ b/protoc_plugin/protos/google/protobuf/compiler/plugin.proto @@ -24,11 +24,11 @@ package google.protobuf.compiler; option java_package = "com.google.protobuf.compiler"; option java_outer_classname = "PluginProtos"; +import "google/protobuf/descriptor.proto"; + option csharp_namespace = "Google.Protobuf.Compiler"; option go_package = "google.golang.org/protobuf/types/pluginpb"; -import "google/protobuf/descriptor.proto"; - // The version number of protocol compiler. message Version { optional int32 major = 1; diff --git a/protoc_plugin/protos/google/protobuf/descriptor.proto b/protoc_plugin/protos/google/protobuf/descriptor.proto index cb9bea19..333b7e99 100644 --- a/protoc_plugin/protos/google/protobuf/descriptor.proto +++ b/protoc_plugin/protos/google/protobuf/descriptor.proto @@ -398,6 +398,9 @@ message ServiceDescriptorProto { repeated MethodDescriptorProto method = 2; optional ServiceOptions options = 3; + + reserved 4; + reserved "stream"; } // Describes a method of a service. @@ -753,8 +756,9 @@ message FieldOptions { // is a formalization for deprecating fields. optional bool deprecated = 3 [default = false]; + // DEPRECATED. DO NOT USE! // For Google-internal migration only. Do not use. - optional bool weak = 10 [default = false]; + optional bool weak = 10 [default = false, deprecated = true]; // Indicate that the field value should not be printed out when using debug // formats, e.g. when the field contains sensitive credentials. From 4a9d582d02b338a5f03078ed2f9ddeddf3757095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 09:56:32 +0100 Subject: [PATCH 02/16] Generate unittest_features proto --- .../google/protobuf/unittest_features.pb.dart | 399 ++++++++++++++++++ .../protobuf/unittest_features.pbenum.dart | 117 +++++ .../google/protobuf/unittest_features.proto | 244 +++++++++++ protoc_plugin/tool/update_protos.dart | 1 + 4 files changed, 761 insertions(+) create mode 100644 protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pb.dart create mode 100644 protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pbenum.dart create mode 100644 protoc_plugin/protos/google/protobuf/unittest_features.proto diff --git a/protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pb.dart b/protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pb.dart new file mode 100644 index 00000000..014f4b8f --- /dev/null +++ b/protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pb.dart @@ -0,0 +1,399 @@ +// This is a generated file - do not edit. +// +// Generated from google/protobuf/unittest_features.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'unittest_features.pbenum.dart'; + +export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions; + +export 'unittest_features.pbenum.dart'; + +class TestMessage_Nested extends $pb.GeneratedMessage { + factory TestMessage_Nested() => create(); + + TestMessage_Nested._(); + + factory TestMessage_Nested.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TestMessage_Nested.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TestMessage.Nested', + package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), + createEmptyInstance: create) + ..hasRequiredFields = false; + static final testNested = $pb.Extension( + _omitMessageNames ? '' : 'google.protobuf.FeatureSet', + _omitFieldNames ? '' : 'testNested', + 9997, + $pb.PbFieldType.OM, + defaultOrMaker: TestFeatures.getDefault, + subBuilder: TestFeatures.create); + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TestMessage_Nested clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TestMessage_Nested copyWith(void Function(TestMessage_Nested) updates) => + super.copyWith((message) => updates(message as TestMessage_Nested)) + as TestMessage_Nested; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TestMessage_Nested create() => TestMessage_Nested._(); + @$core.override + TestMessage_Nested createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static TestMessage_Nested getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TestMessage_Nested? _defaultInstance; +} + +class TestMessage extends $pb.GeneratedMessage { + factory TestMessage() => create(); + + TestMessage._(); + + factory TestMessage.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TestMessage.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TestMessage', + package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), + createEmptyInstance: create) + ..hasRequiredFields = false; + static final testMessage = $pb.Extension( + _omitMessageNames ? '' : 'google.protobuf.FeatureSet', + _omitFieldNames ? '' : 'testMessage', + 9998, + $pb.PbFieldType.OM, + defaultOrMaker: TestFeatures.getDefault, + subBuilder: TestFeatures.create); + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TestMessage clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TestMessage copyWith(void Function(TestMessage) updates) => + super.copyWith((message) => updates(message as TestMessage)) + as TestMessage; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TestMessage create() => TestMessage._(); + @$core.override + TestMessage createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static TestMessage getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TestMessage? _defaultInstance; +} + +class TestFeatures extends $pb.GeneratedMessage { + factory TestFeatures({ + EnumFeature? fileFeature, + EnumFeature? extensionRangeFeature, + EnumFeature? messageFeature, + EnumFeature? fieldFeature, + EnumFeature? oneofFeature, + EnumFeature? enumFeature, + EnumFeature? enumEntryFeature, + EnumFeature? serviceFeature, + EnumFeature? methodFeature, + EnumFeature? multipleFeature, + $core.bool? boolFieldFeature, + EnumFeature? sourceFeature, + EnumFeature? sourceFeature2, + EnumFeature? removedFeature, + EnumFeature? futureFeature, + EnumFeature? legacyFeature, + ValueLifetimeFeature? valueLifetimeFeature, + }) { + final result = create(); + if (fileFeature != null) result.fileFeature = fileFeature; + if (extensionRangeFeature != null) + result.extensionRangeFeature = extensionRangeFeature; + if (messageFeature != null) result.messageFeature = messageFeature; + if (fieldFeature != null) result.fieldFeature = fieldFeature; + if (oneofFeature != null) result.oneofFeature = oneofFeature; + if (enumFeature != null) result.enumFeature = enumFeature; + if (enumEntryFeature != null) result.enumEntryFeature = enumEntryFeature; + if (serviceFeature != null) result.serviceFeature = serviceFeature; + if (methodFeature != null) result.methodFeature = methodFeature; + if (multipleFeature != null) result.multipleFeature = multipleFeature; + if (boolFieldFeature != null) result.boolFieldFeature = boolFieldFeature; + if (sourceFeature != null) result.sourceFeature = sourceFeature; + if (sourceFeature2 != null) result.sourceFeature2 = sourceFeature2; + if (removedFeature != null) result.removedFeature = removedFeature; + if (futureFeature != null) result.futureFeature = futureFeature; + if (legacyFeature != null) result.legacyFeature = legacyFeature; + if (valueLifetimeFeature != null) + result.valueLifetimeFeature = valueLifetimeFeature; + return result; + } + + TestFeatures._(); + + factory TestFeatures.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TestFeatures.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TestFeatures', + package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), + createEmptyInstance: create) + ..aE(1, _omitFieldNames ? '' : 'fileFeature', + enumValues: EnumFeature.values) + ..aE(2, _omitFieldNames ? '' : 'extensionRangeFeature', + enumValues: EnumFeature.values) + ..aE(3, _omitFieldNames ? '' : 'messageFeature', + enumValues: EnumFeature.values) + ..aE(4, _omitFieldNames ? '' : 'fieldFeature', + enumValues: EnumFeature.values) + ..aE(5, _omitFieldNames ? '' : 'oneofFeature', + enumValues: EnumFeature.values) + ..aE(6, _omitFieldNames ? '' : 'enumFeature', + enumValues: EnumFeature.values) + ..aE(7, _omitFieldNames ? '' : 'enumEntryFeature', + enumValues: EnumFeature.values) + ..aE(8, _omitFieldNames ? '' : 'serviceFeature', + enumValues: EnumFeature.values) + ..aE(9, _omitFieldNames ? '' : 'methodFeature', + enumValues: EnumFeature.values) + ..aE(10, _omitFieldNames ? '' : 'multipleFeature', + enumValues: EnumFeature.values) + ..aOB(11, _omitFieldNames ? '' : 'boolFieldFeature') + ..aE(15, _omitFieldNames ? '' : 'sourceFeature', + enumValues: EnumFeature.values) + ..aE(16, _omitFieldNames ? '' : 'sourceFeature2', + enumValues: EnumFeature.values) + ..aE(17, _omitFieldNames ? '' : 'removedFeature', + enumValues: EnumFeature.values) + ..aE(18, _omitFieldNames ? '' : 'futureFeature', + enumValues: EnumFeature.values) + ..aE(19, _omitFieldNames ? '' : 'legacyFeature', + enumValues: EnumFeature.values) + ..aE( + 20, _omitFieldNames ? '' : 'valueLifetimeFeature', + enumValues: ValueLifetimeFeature.values) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TestFeatures clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TestFeatures copyWith(void Function(TestFeatures) updates) => + super.copyWith((message) => updates(message as TestFeatures)) + as TestFeatures; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TestFeatures create() => TestFeatures._(); + @$core.override + TestFeatures createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static TestFeatures getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TestFeatures? _defaultInstance; + + @$pb.TagNumber(1) + EnumFeature get fileFeature => $_getN(0); + @$pb.TagNumber(1) + set fileFeature(EnumFeature value) => $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasFileFeature() => $_has(0); + @$pb.TagNumber(1) + void clearFileFeature() => $_clearField(1); + + @$pb.TagNumber(2) + EnumFeature get extensionRangeFeature => $_getN(1); + @$pb.TagNumber(2) + set extensionRangeFeature(EnumFeature value) => $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasExtensionRangeFeature() => $_has(1); + @$pb.TagNumber(2) + void clearExtensionRangeFeature() => $_clearField(2); + + @$pb.TagNumber(3) + EnumFeature get messageFeature => $_getN(2); + @$pb.TagNumber(3) + set messageFeature(EnumFeature value) => $_setField(3, value); + @$pb.TagNumber(3) + $core.bool hasMessageFeature() => $_has(2); + @$pb.TagNumber(3) + void clearMessageFeature() => $_clearField(3); + + @$pb.TagNumber(4) + EnumFeature get fieldFeature => $_getN(3); + @$pb.TagNumber(4) + set fieldFeature(EnumFeature value) => $_setField(4, value); + @$pb.TagNumber(4) + $core.bool hasFieldFeature() => $_has(3); + @$pb.TagNumber(4) + void clearFieldFeature() => $_clearField(4); + + @$pb.TagNumber(5) + EnumFeature get oneofFeature => $_getN(4); + @$pb.TagNumber(5) + set oneofFeature(EnumFeature value) => $_setField(5, value); + @$pb.TagNumber(5) + $core.bool hasOneofFeature() => $_has(4); + @$pb.TagNumber(5) + void clearOneofFeature() => $_clearField(5); + + @$pb.TagNumber(6) + EnumFeature get enumFeature => $_getN(5); + @$pb.TagNumber(6) + set enumFeature(EnumFeature value) => $_setField(6, value); + @$pb.TagNumber(6) + $core.bool hasEnumFeature() => $_has(5); + @$pb.TagNumber(6) + void clearEnumFeature() => $_clearField(6); + + @$pb.TagNumber(7) + EnumFeature get enumEntryFeature => $_getN(6); + @$pb.TagNumber(7) + set enumEntryFeature(EnumFeature value) => $_setField(7, value); + @$pb.TagNumber(7) + $core.bool hasEnumEntryFeature() => $_has(6); + @$pb.TagNumber(7) + void clearEnumEntryFeature() => $_clearField(7); + + @$pb.TagNumber(8) + EnumFeature get serviceFeature => $_getN(7); + @$pb.TagNumber(8) + set serviceFeature(EnumFeature value) => $_setField(8, value); + @$pb.TagNumber(8) + $core.bool hasServiceFeature() => $_has(7); + @$pb.TagNumber(8) + void clearServiceFeature() => $_clearField(8); + + @$pb.TagNumber(9) + EnumFeature get methodFeature => $_getN(8); + @$pb.TagNumber(9) + set methodFeature(EnumFeature value) => $_setField(9, value); + @$pb.TagNumber(9) + $core.bool hasMethodFeature() => $_has(8); + @$pb.TagNumber(9) + void clearMethodFeature() => $_clearField(9); + + @$pb.TagNumber(10) + EnumFeature get multipleFeature => $_getN(9); + @$pb.TagNumber(10) + set multipleFeature(EnumFeature value) => $_setField(10, value); + @$pb.TagNumber(10) + $core.bool hasMultipleFeature() => $_has(9); + @$pb.TagNumber(10) + void clearMultipleFeature() => $_clearField(10); + + @$pb.TagNumber(11) + $core.bool get boolFieldFeature => $_getBF(10); + @$pb.TagNumber(11) + set boolFieldFeature($core.bool value) => $_setBool(10, value); + @$pb.TagNumber(11) + $core.bool hasBoolFieldFeature() => $_has(10); + @$pb.TagNumber(11) + void clearBoolFieldFeature() => $_clearField(11); + + @$pb.TagNumber(15) + EnumFeature get sourceFeature => $_getN(11); + @$pb.TagNumber(15) + set sourceFeature(EnumFeature value) => $_setField(15, value); + @$pb.TagNumber(15) + $core.bool hasSourceFeature() => $_has(11); + @$pb.TagNumber(15) + void clearSourceFeature() => $_clearField(15); + + @$pb.TagNumber(16) + EnumFeature get sourceFeature2 => $_getN(12); + @$pb.TagNumber(16) + set sourceFeature2(EnumFeature value) => $_setField(16, value); + @$pb.TagNumber(16) + $core.bool hasSourceFeature2() => $_has(12); + @$pb.TagNumber(16) + void clearSourceFeature2() => $_clearField(16); + + @$pb.TagNumber(17) + EnumFeature get removedFeature => $_getN(13); + @$pb.TagNumber(17) + set removedFeature(EnumFeature value) => $_setField(17, value); + @$pb.TagNumber(17) + $core.bool hasRemovedFeature() => $_has(13); + @$pb.TagNumber(17) + void clearRemovedFeature() => $_clearField(17); + + @$pb.TagNumber(18) + EnumFeature get futureFeature => $_getN(14); + @$pb.TagNumber(18) + set futureFeature(EnumFeature value) => $_setField(18, value); + @$pb.TagNumber(18) + $core.bool hasFutureFeature() => $_has(14); + @$pb.TagNumber(18) + void clearFutureFeature() => $_clearField(18); + + @$pb.TagNumber(19) + EnumFeature get legacyFeature => $_getN(15); + @$pb.TagNumber(19) + set legacyFeature(EnumFeature value) => $_setField(19, value); + @$pb.TagNumber(19) + $core.bool hasLegacyFeature() => $_has(15); + @$pb.TagNumber(19) + void clearLegacyFeature() => $_clearField(19); + + @$pb.TagNumber(20) + ValueLifetimeFeature get valueLifetimeFeature => $_getN(16); + @$pb.TagNumber(20) + set valueLifetimeFeature(ValueLifetimeFeature value) => $_setField(20, value); + @$pb.TagNumber(20) + $core.bool hasValueLifetimeFeature() => $_has(16); + @$pb.TagNumber(20) + void clearValueLifetimeFeature() => $_clearField(20); +} + +class Unittest_features { + static final test = $pb.Extension( + _omitMessageNames ? '' : 'google.protobuf.FeatureSet', + _omitFieldNames ? '' : 'test', + 9999, + $pb.PbFieldType.OM, + defaultOrMaker: TestFeatures.getDefault, + subBuilder: TestFeatures.create); + static void registerAllExtensions($pb.ExtensionRegistry registry) { + registry.add(test); + } +} + +const $core.bool _omitFieldNames = + $core.bool.fromEnvironment('protobuf.omit_field_names'); +const $core.bool _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pbenum.dart b/protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pbenum.dart new file mode 100644 index 00000000..2aea267d --- /dev/null +++ b/protoc_plugin/lib/src/gen/google/protobuf/unittest_features.pbenum.dart @@ -0,0 +1,117 @@ +// This is a generated file - do not edit. +// +// Generated from google/protobuf/unittest_features.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class EnumFeature extends $pb.ProtobufEnum { + static const EnumFeature TEST_ENUM_FEATURE_UNKNOWN = + EnumFeature._(0, _omitEnumNames ? '' : 'TEST_ENUM_FEATURE_UNKNOWN'); + static const EnumFeature VALUE1 = + EnumFeature._(1, _omitEnumNames ? '' : 'VALUE1'); + static const EnumFeature VALUE2 = + EnumFeature._(2, _omitEnumNames ? '' : 'VALUE2'); + static const EnumFeature VALUE3 = + EnumFeature._(3, _omitEnumNames ? '' : 'VALUE3'); + static const EnumFeature VALUE4 = + EnumFeature._(4, _omitEnumNames ? '' : 'VALUE4'); + static const EnumFeature VALUE5 = + EnumFeature._(5, _omitEnumNames ? '' : 'VALUE5'); + static const EnumFeature VALUE6 = + EnumFeature._(6, _omitEnumNames ? '' : 'VALUE6'); + static const EnumFeature VALUE7 = + EnumFeature._(7, _omitEnumNames ? '' : 'VALUE7'); + static const EnumFeature VALUE8 = + EnumFeature._(8, _omitEnumNames ? '' : 'VALUE8'); + static const EnumFeature VALUE9 = + EnumFeature._(9, _omitEnumNames ? '' : 'VALUE9'); + static const EnumFeature VALUE10 = + EnumFeature._(10, _omitEnumNames ? '' : 'VALUE10'); + static const EnumFeature VALUE11 = + EnumFeature._(11, _omitEnumNames ? '' : 'VALUE11'); + static const EnumFeature VALUE12 = + EnumFeature._(12, _omitEnumNames ? '' : 'VALUE12'); + static const EnumFeature VALUE13 = + EnumFeature._(13, _omitEnumNames ? '' : 'VALUE13'); + static const EnumFeature VALUE14 = + EnumFeature._(14, _omitEnumNames ? '' : 'VALUE14'); + static const EnumFeature VALUE15 = + EnumFeature._(15, _omitEnumNames ? '' : 'VALUE15'); + + static const $core.List values = [ + TEST_ENUM_FEATURE_UNKNOWN, + VALUE1, + VALUE2, + VALUE3, + VALUE4, + VALUE5, + VALUE6, + VALUE7, + VALUE8, + VALUE9, + VALUE10, + VALUE11, + VALUE12, + VALUE13, + VALUE14, + VALUE15, + ]; + + static final $core.List _byValue = + $pb.ProtobufEnum.$_initByValueList(values, 15); + static EnumFeature? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const EnumFeature._(super.value, super.name); +} + +class ValueLifetimeFeature extends $pb.ProtobufEnum { + static const ValueLifetimeFeature TEST_VALUE_LIFETIME_UNKNOWN = + ValueLifetimeFeature._( + 0, _omitEnumNames ? '' : 'TEST_VALUE_LIFETIME_UNKNOWN'); + static const ValueLifetimeFeature VALUE_LIFETIME_INHERITED = + ValueLifetimeFeature._( + 1, _omitEnumNames ? '' : 'VALUE_LIFETIME_INHERITED'); + static const ValueLifetimeFeature VALUE_LIFETIME_SUPPORT = + ValueLifetimeFeature._(2, _omitEnumNames ? '' : 'VALUE_LIFETIME_SUPPORT'); + static const ValueLifetimeFeature VALUE_LIFETIME_EMPTY_SUPPORT = + ValueLifetimeFeature._( + 3, _omitEnumNames ? '' : 'VALUE_LIFETIME_EMPTY_SUPPORT'); + static const ValueLifetimeFeature VALUE_LIFETIME_FUTURE = + ValueLifetimeFeature._(4, _omitEnumNames ? '' : 'VALUE_LIFETIME_FUTURE'); + static const ValueLifetimeFeature VALUE_LIFETIME_DEPRECATED = + ValueLifetimeFeature._( + 5, _omitEnumNames ? '' : 'VALUE_LIFETIME_DEPRECATED'); + static const ValueLifetimeFeature VALUE_LIFETIME_REMOVED = + ValueLifetimeFeature._(6, _omitEnumNames ? '' : 'VALUE_LIFETIME_REMOVED'); + + static const $core.List values = [ + TEST_VALUE_LIFETIME_UNKNOWN, + VALUE_LIFETIME_INHERITED, + VALUE_LIFETIME_SUPPORT, + VALUE_LIFETIME_EMPTY_SUPPORT, + VALUE_LIFETIME_FUTURE, + VALUE_LIFETIME_DEPRECATED, + VALUE_LIFETIME_REMOVED, + ]; + + static final $core.List _byValue = + $pb.ProtobufEnum.$_initByValueList(values, 6); + static ValueLifetimeFeature? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const ValueLifetimeFeature._(super.value, super.name); +} + +const $core.bool _omitEnumNames = + $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/protoc_plugin/protos/google/protobuf/unittest_features.proto b/protoc_plugin/protos/google/protobuf/unittest_features.proto new file mode 100644 index 00000000..dd0d4141 --- /dev/null +++ b/protoc_plugin/protos/google/protobuf/unittest_features.proto @@ -0,0 +1,244 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +edition = "2024"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +option java_outer_classname = "UnittestFeatures"; + +extend google.protobuf.FeatureSet { + TestFeatures test = 9999; +} + +message TestMessage { + extend google.protobuf.FeatureSet { + TestFeatures test_message = 9998; + } + message Nested { + extend google.protobuf.FeatureSet { + TestFeatures test_nested = 9997; + } + } +} + +enum EnumFeature { + TEST_ENUM_FEATURE_UNKNOWN = 0; + VALUE1 = 1; + VALUE2 = 2; + VALUE3 = 3; + VALUE4 = 4; + VALUE5 = 5; + VALUE6 = 6; + VALUE7 = 7; + VALUE8 = 8; + VALUE9 = 9; + VALUE10 = 10; + VALUE11 = 11; + VALUE12 = 12; + VALUE13 = 13; + VALUE14 = 14; + VALUE15 = 15; +} + +enum ValueLifetimeFeature { + TEST_VALUE_LIFETIME_UNKNOWN = 0; + VALUE_LIFETIME_INHERITED = 1; + VALUE_LIFETIME_SUPPORT = 2 [feature_support = { + edition_introduced: EDITION_99997_TEST_ONLY + edition_deprecated: EDITION_99998_TEST_ONLY + deprecation_warning: "Custom feature deprecation warning" + edition_removed: EDITION_99999_TEST_ONLY + }]; + VALUE_LIFETIME_EMPTY_SUPPORT = 3 [feature_support = {}]; + VALUE_LIFETIME_FUTURE = 4 + [feature_support.edition_introduced = EDITION_99997_TEST_ONLY]; + VALUE_LIFETIME_DEPRECATED = 5 [feature_support = { + edition_deprecated: EDITION_99997_TEST_ONLY + deprecation_warning: "Custom feature deprecation warning" + }]; + VALUE_LIFETIME_REMOVED = 6 [feature_support = { + edition_deprecated: EDITION_2023 + edition_removed: EDITION_99997_TEST_ONLY + }]; +} + +message TestFeatures { + EnumFeature file_feature = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FILE, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" }, + edition_defaults = { edition: EDITION_PROTO3, value: "VALUE2" }, + edition_defaults = { edition: EDITION_2023, value: "VALUE3" }, + edition_defaults = { edition: EDITION_99997_TEST_ONLY, value: "VALUE4" }, + edition_defaults = { edition: EDITION_99998_TEST_ONLY, value: "VALUE5" } + ]; + EnumFeature extension_range_feature = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_EXTENSION_RANGE, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature message_feature = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature field_feature = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature oneof_feature = 5 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ONEOF, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature enum_feature = 6 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature enum_entry_feature = 7 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM_ENTRY, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature service_feature = 8 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_SERVICE, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature method_feature = 9 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_METHOD, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + EnumFeature multiple_feature = 10 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FILE, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_ENUM_ENTRY, + targets = TARGET_TYPE_SERVICE, + targets = TARGET_TYPE_METHOD, + targets = TARGET_TYPE_ONEOF, + targets = TARGET_TYPE_EXTENSION_RANGE, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + + bool bool_field_feature = 11 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "false" }, + edition_defaults = { edition: EDITION_99997_TEST_ONLY, value: "true" } + ]; + + EnumFeature source_feature = 15 [ + retention = RETENTION_SOURCE, + targets = TARGET_TYPE_FILE, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_ENUM_ENTRY, + targets = TARGET_TYPE_SERVICE, + targets = TARGET_TYPE_METHOD, + targets = TARGET_TYPE_ONEOF, + targets = TARGET_TYPE_EXTENSION_RANGE, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + + EnumFeature source_feature2 = 16 [ + retention = RETENTION_SOURCE, + targets = TARGET_TYPE_FILE, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_ENUM_ENTRY, + targets = TARGET_TYPE_SERVICE, + targets = TARGET_TYPE_METHOD, + targets = TARGET_TYPE_ONEOF, + targets = TARGET_TYPE_EXTENSION_RANGE, + feature_support.edition_introduced = EDITION_2023, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" } + ]; + + EnumFeature removed_feature = 17 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FILE, + targets = TARGET_TYPE_FIELD, + feature_support = { + edition_introduced: EDITION_2023 + edition_deprecated: EDITION_2023 + deprecation_warning: "Custom feature deprecation warning" + edition_removed: EDITION_2024 + }, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" }, + edition_defaults = { edition: EDITION_2023, value: "VALUE2" }, + edition_defaults = { edition: EDITION_2024, value: "VALUE3" } + ]; + + EnumFeature future_feature = 18 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FILE, + targets = TARGET_TYPE_FIELD, + feature_support = { edition_introduced: EDITION_2024 }, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" }, + edition_defaults = { edition: EDITION_2024, value: "VALUE2" } + ]; + + EnumFeature legacy_feature = 19 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FILE, + targets = TARGET_TYPE_FIELD, + feature_support = { + edition_introduced: EDITION_PROTO3 + edition_removed: EDITION_2023 + }, + edition_defaults = { edition: EDITION_LEGACY, value: "VALUE1" }, + edition_defaults = { edition: EDITION_2023, value: "VALUE2" } + ]; + + ValueLifetimeFeature value_lifetime_feature = 20 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023 + edition_deprecated: EDITION_99998_TEST_ONLY + deprecation_warning: "Custom feature deprecation warning" + edition_removed: EDITION_99999_TEST_ONLY + }, + edition_defaults = { + edition: EDITION_LEGACY, + value: "VALUE_LIFETIME_INHERITED" + }, + // Verify edition defaults can use future values. + edition_defaults = { + edition: EDITION_2023, + value: "VALUE_LIFETIME_FUTURE" + }, + // Verify edition defaults can use removed values. + edition_defaults = { + edition: EDITION_99999_TEST_ONLY, + value: "VALUE_LIFETIME_FUTURE" + } + ]; +} diff --git a/protoc_plugin/tool/update_protos.dart b/protoc_plugin/tool/update_protos.dart index cd3f2214..c0ff6e25 100644 --- a/protoc_plugin/tool/update_protos.dart +++ b/protoc_plugin/tool/update_protos.dart @@ -31,6 +31,7 @@ void main(List args) async { 'google/protobuf/compiler/plugin.proto', 'google/protobuf/descriptor.proto', 'google/protobuf/duration.proto', + 'google/protobuf/unittest_features.proto', ]); // Update from googleapis/googleapis. From a8c01dcde6b5b27f9fbd4a4acfb401da63eb8307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Mon, 15 Sep 2025 12:13:30 +0100 Subject: [PATCH 03/16] Sync edition support --- protoc_plugin/Makefile | 1 + protoc_plugin/lib/names.dart | 36 +++- protoc_plugin/lib/protoc.dart | 7 + protoc_plugin/lib/src/base_type.dart | 22 +- protoc_plugin/lib/src/code_generator.dart | 25 ++- protoc_plugin/lib/src/enum_generator.dart | 6 +- .../lib/src/extension_generator.dart | 4 +- protoc_plugin/lib/src/file_generator.dart | 68 ++++++- protoc_plugin/lib/src/message_generator.dart | 57 ++++-- protoc_plugin/lib/src/protobuf_field.dart | 80 +++++--- protoc_plugin/lib/src/service_generator.dart | 2 +- protoc_plugin/test/client_generator_test.dart | 5 +- protoc_plugin/test/enum_generator_test.dart | 60 +++++- .../test/extension_generator_test.dart | 90 ++++++-- protoc_plugin/test/file_generator_test.dart | 141 +++++++++++-- protoc_plugin/test/goldens/enum | 1 + protoc_plugin/test/goldens/enum.meta | 43 ++++ protoc_plugin/test/goldens/extension | 1 + protoc_plugin/test/goldens/extension.meta | 7 + protoc_plugin/test/import_option_test.dart | 34 ++++ .../test/message_generator_test.dart | 192 +++++++++++++++++- .../test/protos/custom_option_unlinked.proto | 15 ++ protoc_plugin/test/protos/import_option.proto | 13 ++ protoc_plugin/test/src/test_features.dart | 25 +++ 24 files changed, 826 insertions(+), 109 deletions(-) create mode 100644 protoc_plugin/test/goldens/enum create mode 100644 protoc_plugin/test/goldens/enum.meta create mode 100644 protoc_plugin/test/goldens/extension create mode 100644 protoc_plugin/test/goldens/extension.meta create mode 100644 protoc_plugin/test/import_option_test.dart create mode 100644 protoc_plugin/test/protos/custom_option_unlinked.proto create mode 100644 protoc_plugin/test/protos/import_option.proto create mode 100644 protoc_plugin/test/src/test_features.dart diff --git a/protoc_plugin/Makefile b/protoc_plugin/Makefile index 18aaa658..b3121ff2 100644 --- a/protoc_plugin/Makefile +++ b/protoc_plugin/Makefile @@ -39,6 +39,7 @@ TEST_PROTO_LIST = \ foo \ high_tagnumber \ import_clash \ + import_option \ import_public \ json_name \ map_api \ diff --git a/protoc_plugin/lib/names.dart b/protoc_plugin/lib/names.dart index cf176a70..e14495d4 100644 --- a/protoc_plugin/lib/names.dart +++ b/protoc_plugin/lib/names.dart @@ -117,8 +117,18 @@ String singleQuote(String input) { } /// Chooses the Dart name of an extension. -String extensionName(FieldDescriptorProto descriptor, Set usedNames) { - return _unusedMemberNames(descriptor, null, null, usedNames).fieldName; +String extensionName( + FieldDescriptorProto descriptor, + Set usedNames, + bool lowercaseGroupNames, +) { + return _unusedMemberNames( + descriptor, + null, + null, + usedNames, + lowercaseGroupNames, + ).fieldName; } Iterable extensionSuffixes() sync* { @@ -281,6 +291,7 @@ MemberNames messageMemberNames( String parentClassName, Set usedTopLevelNames, { Iterable reserved = const [], + bool lowercaseGroupNames = false, }) { final fieldList = List.from(descriptor.field); final sourcePositions = fieldList.asMap().map( @@ -340,7 +351,13 @@ MemberNames messageMemberNames( final index = indexes[field.name]!; final sourcePosition = sourcePositions[field.name]; takeFieldNames( - _unusedMemberNames(field, index, sourcePosition, existingNames), + _unusedMemberNames( + field, + index, + sourcePosition, + existingNames, + lowercaseGroupNames, + ), ); } } @@ -470,6 +487,7 @@ FieldNames _unusedMemberNames( int? index, int? sourcePosition, Set existingNames, + bool lowercaseGroupNames, ) { if (_isRepeated(field)) { return FieldNames( @@ -477,7 +495,7 @@ FieldNames _unusedMemberNames( index, sourcePosition, disambiguateName( - _defaultFieldName(_fieldMethodSuffix(field)), + _defaultFieldName(_fieldMethodSuffix(field, lowercaseGroupNames)), existingNames, _memberNamesSuffix(field.number), ), @@ -498,7 +516,7 @@ FieldNames _unusedMemberNames( } final name = disambiguateName( - _fieldMethodSuffix(field), + _fieldMethodSuffix(field, lowercaseGroupNames), existingNames, _memberNamesSuffix(field.number), generateVariants: generateNameVariants, @@ -535,11 +553,15 @@ String _defaultEnsureMethodName(String fieldMethodSuffix) => /// The suffix to use for this field in Dart method names. /// (It should be camelcase and begin with an uppercase letter.) -String _fieldMethodSuffix(FieldDescriptorProto field) { +String _fieldMethodSuffix( + FieldDescriptorProto field, + bool lowercaseGroupNames, +) { var name = _nameOption(field)!; if (name.isNotEmpty) return _capitalize(name); - if (field.type != FieldDescriptorProto_Type.TYPE_GROUP) { + if (field.type != FieldDescriptorProto_Type.TYPE_GROUP || + lowercaseGroupNames) { return underscoresToCamelCase(field.name); } diff --git a/protoc_plugin/lib/protoc.dart b/protoc_plugin/lib/protoc.dart index 36731a50..4a7d156b 100644 --- a/protoc_plugin/lib/protoc.dart +++ b/protoc_plugin/lib/protoc.dart @@ -34,3 +34,10 @@ part 'src/paths.dart'; part 'src/protobuf_field.dart'; part 'src/service_generator.dart'; part 'src/well_known_types.dart'; + +const _protobufInternalDartEditionDefaults = + 'ChcYhAciACoQCAEQAhgCIAMoATACOAJAAQoXGOcHIgAqEAgCEAEYASACKAEwATgCQAEKFxjoByIMCAEQARgBIAIoATABKgQ4AkABChcY6QciEAgBEAEYASACKAEwATgBQAIqACDmByjpBw=='; + +FeatureSetDefaults pluginFeatureSetDefaults = FeatureSetDefaults.fromBuffer( + base64Decode(_protobufInternalDartEditionDefaults), +); diff --git a/protoc_plugin/lib/src/base_type.dart b/protoc_plugin/lib/src/base_type.dart index 0f5d08c6..fc1d33c3 100644 --- a/protoc_plugin/lib/src/base_type.dart +++ b/protoc_plugin/lib/src/base_type.dart @@ -65,8 +65,13 @@ class BaseType { String getRepeatedDartTypeIterable(FileGenerator fileGen) => '$coreImportPrefix.Iterable<${getDartType(fileGen)}>'; - factory BaseType(FieldDescriptorProto field, GenerationContext ctx) { + factory BaseType( + FieldDescriptorProto field, + FeatureSet features, + GenerationContext ctx, + ) { String constSuffix; + FieldDescriptorProto_Type type; switch (field.type) { case FieldDescriptorProto_Type.TYPE_BOOL: @@ -191,14 +196,17 @@ class BaseType { ); case FieldDescriptorProto_Type.TYPE_GROUP: - constSuffix = 'G'; - break; case FieldDescriptorProto_Type.TYPE_MESSAGE: - constSuffix = 'M'; - break; + if (features.messageEncoding == FeatureSet_MessageEncoding.DELIMITED) { + constSuffix = 'G'; + type = FieldDescriptorProto_Type.TYPE_GROUP; + } else { + constSuffix = 'M'; + type = FieldDescriptorProto_Type.TYPE_MESSAGE; + } case FieldDescriptorProto_Type.TYPE_ENUM: constSuffix = 'E'; - break; + type = FieldDescriptorProto_Type.TYPE_ENUM; default: throw ArgumentError('unimplemented type: ${field.type.name}'); @@ -210,7 +218,7 @@ class BaseType { } return BaseType._raw( - field.type, + type, constSuffix, generator.classname!, null, diff --git a/protoc_plugin/lib/src/code_generator.dart b/protoc_plugin/lib/src/code_generator.dart index 8d4acad0..6bb90c53 100644 --- a/protoc_plugin/lib/src/code_generator.dart +++ b/protoc_plugin/lib/src/code_generator.dart @@ -10,10 +10,11 @@ import 'package:fixnum/fixnum.dart'; import 'package:protobuf/protobuf.dart'; import '../names.dart' show lowerCaseFirstLetter; -import '../protoc.dart' show FileGenerator; +import '../protoc.dart' show FileGenerator, pluginFeatureSetDefaults; import 'gen/dart_options.pb.dart'; import 'gen/google/api/client.pb.dart'; import 'gen/google/protobuf/compiler/plugin.pb.dart'; +import 'gen/google/protobuf/descriptor.pb.dart'; import 'linker.dart'; import 'options.dart'; import 'output_config.dart'; @@ -58,6 +59,8 @@ abstract class ProtobufContainer { // The generator containing this entity. ProtobufContainer? get parent; + FeatureSet get features; + /// The top-level parent of this entity, or itself if it is a top-level /// entity. ProtobufContainer? get toplevelParent { @@ -86,8 +89,8 @@ class CodeGenerator { Map? optionParsers, OutputConfiguration config = const DefaultOutputConfiguration(), }) async { + final editionDefaults = pluginFeatureSetDefaults; final extensions = ExtensionRegistry(); - Dart_options.registerAllExtensions(extensions); Client.registerAllExtensions(extensions); @@ -118,7 +121,7 @@ class CodeGenerator { // (We may import it even if we don't generate the .pb.dart file.) final generators = []; for (final file in request.protoFile) { - generators.add(FileGenerator(file, options)); + generators.add(FileGenerator(editionDefaults, file, options)); } // Collect field types and importable files. @@ -131,9 +134,19 @@ class CodeGenerator { response.file.addAll(gen.generateFiles(config)); } } - response.supportedFeatures = Int64( - CodeGeneratorResponse_Feature.FEATURE_PROTO3_OPTIONAL.value, - ); + response.supportedFeatures = + Int64(CodeGeneratorResponse_Feature.FEATURE_PROTO3_OPTIONAL.value) | + Int64(CodeGeneratorResponse_Feature.FEATURE_SUPPORTS_EDITIONS.value); + response.minimumEdition = Edition.EDITION_PROTO2.value; + response.maximumEdition = Edition.EDITION_2024.value; + + // The edition defaults should always stay synchronized with the + // supported edition range we report to protoc. It's not clear that + // the BUILD file definitions are load-bearing though, so we + // explicitly set them above and assert that the two are equal. + assert(response.minimumEdition == editionDefaults.minimumEdition.value); + assert(response.maximumEdition == editionDefaults.maximumEdition.value); + _streamOut.add(response.writeToBuffer()); } } diff --git a/protoc_plugin/lib/src/enum_generator.dart b/protoc_plugin/lib/src/enum_generator.dart index d7e992a8..d6c0f88d 100644 --- a/protoc_plugin/lib/src/enum_generator.dart +++ b/protoc_plugin/lib/src/enum_generator.dart @@ -14,6 +14,9 @@ class EnumGenerator extends ProtobufContainer { @override final ProtobufContainer parent; + @override + final FeatureSet features; + @override final String classname; @@ -50,7 +53,8 @@ class EnumGenerator extends ProtobufContainer { parent.fullName == '' ? descriptor.name : '${parent.fullName}.${descriptor.name}', - _descriptor = descriptor { + _descriptor = descriptor, + features = resolveFeatures(parent.features, descriptor.options.features) { final usedNames = {...reservedEnumNames}; for (var i = 0; i < descriptor.value.length; i++) { final value = descriptor.value[i]; diff --git a/protoc_plugin/lib/src/extension_generator.dart b/protoc_plugin/lib/src/extension_generator.dart index 229d1052..2f95fa62 100644 --- a/protoc_plugin/lib/src/extension_generator.dart +++ b/protoc_plugin/lib/src/extension_generator.dart @@ -24,7 +24,7 @@ class ExtensionGenerator { Set usedNames, int repeatedFieldIndex, int fieldIdTag, - ) : _extensionName = extensionName(_descriptor, usedNames), + ) : _extensionName = extensionName(_descriptor, usedNames, false), _fieldPathSegment = [fieldIdTag, repeatedFieldIndex]; static const _topLevelFieldTag = 7; @@ -71,6 +71,8 @@ class ExtensionGenerator { /// The generator of the .pb.dart file where this extension will be defined. FileGenerator? get fileGen => _parent.fileGen; + FeatureSet get features => _field.features; + String get name { if (!_resolved) throw StateError('resolve not called'); final name = _extensionName; diff --git a/protoc_plugin/lib/src/file_generator.dart b/protoc_plugin/lib/src/file_generator.dart index 63674687..8cba0c49 100644 --- a/protoc_plugin/lib/src/file_generator.dart +++ b/protoc_plugin/lib/src/file_generator.dart @@ -18,8 +18,6 @@ const String _protobufImportUrl = 'package:protobuf/protobuf.dart'; const String _typedDataImportPrefix = r'$typed_data'; const String _typedDataImportUrl = 'dart:typed_data'; -enum ProtoSyntax { proto2, proto3 } - /// Generates the Dart output files for one .proto input file. /// /// Outputs include .pb.dart, pbenum.dart, and .pbjson.dart. @@ -140,14 +138,21 @@ class FileGenerator extends ProtobufContainer { /// Whether cross-references have been resolved. bool _linked = false; - final ProtoSyntax syntax; + final Edition edition; - FileGenerator(this.descriptor, this.options) - : protoFileUri = Uri.file(descriptor.name), - syntax = - descriptor.syntax == 'proto3' - ? ProtoSyntax.proto3 - : ProtoSyntax.proto2 { + @override + final FeatureSet features; + + FileGenerator( + FeatureSetDefaults editionDefaults, + this.descriptor, + this.options, + ) : protoFileUri = Uri.file(descriptor.name), + edition = _getEdition(descriptor), + features = resolveFeatures( + _getEditionDefaults(editionDefaults, _getEdition(descriptor)), + descriptor.options.features, + ) { if (protoFileUri.isAbsolute) { // protoc should never generate an import with an absolute path. throw 'FAILURE: Import with absolute path is not supported'; @@ -825,6 +830,51 @@ class ConditionalConstDefinition { } } +Edition _getEdition(FileDescriptorProto file) { + if (file.edition != Edition.EDITION_UNKNOWN) { + return file.edition; + } + if (file.syntax == 'proto3') { + return Edition.EDITION_PROTO3; + } + return Edition.EDITION_PROTO2; +} + +FeatureSet resolveFeatures(FeatureSet parent, FeatureSet child) { + final result = parent.clone(); + result.mergeFromMessage(child); + return result; +} + +FeatureSet _getEditionDefaults( + FeatureSetDefaults editionDefaults, + Edition edition, +) { + if (edition.value < editionDefaults.minimumEdition.value) { + throw ArgumentError( + 'Edition $edition is earlier than the minimum supported edition ${editionDefaults.minimumEdition}!', + ); + } + if (edition.value > editionDefaults.maximumEdition.value) { + throw ArgumentError( + 'Edition $edition is later than the maximum supported edition ${editionDefaults.maximumEdition}!', + ); + } + FeatureSetDefaults_FeatureSetEditionDefault? found; + for (final d in editionDefaults.defaults) { + if (d.edition.value > edition.value) { + break; + } + found = d; + } + if (found == null) { + throw ArgumentError('No default found for edition $edition!'); + } + final defaults = found.fixedFeatures.clone(); + defaults.mergeFromMessage(found.overridableFeatures); + return defaults; +} + const _fileIgnores = { 'annotate_overrides', 'camel_case_types', diff --git a/protoc_plugin/lib/src/message_generator.dart b/protoc_plugin/lib/src/message_generator.dart index 9345584d..1ff7bea5 100644 --- a/protoc_plugin/lib/src/message_generator.dart +++ b/protoc_plugin/lib/src/message_generator.dart @@ -76,6 +76,9 @@ class MessageGenerator extends ProtobufContainer { @override final ProtobufContainer parent; + @override + final FeatureSet features; + final DescriptorProto _descriptor; final List _enumGenerators = []; final List _messageGenerators = []; @@ -85,13 +88,14 @@ class MessageGenerator extends ProtobufContainer { /// by the index in the containing types's oneof_decl list. /// Only contains the 'real' oneofs. final List> _oneofFields; + final List _oneofFeatures; late List _oneofNames; @override final List fieldPath; // populated by resolve() - late List _fieldList; + late List fieldList; bool _resolved = false; Set _usedTopLevelNames; @@ -116,7 +120,12 @@ class MessageGenerator extends ProtobufContainer { _oneofFields = List.generate( countRealOneofs(descriptor), (int index) => [], - ) { + ), + _oneofFeatures = List.generate( + countRealOneofs(descriptor), + (int index) => FeatureSet(), + ), + features = resolveFeatures(parent.features, descriptor.options.features) { mixin = _getMixin(declaredMixins, defaultMixin); for (var i = 0; i < _descriptor.enumType.length; i++) { final e = _descriptor.enumType[i]; @@ -137,6 +146,13 @@ class MessageGenerator extends ProtobufContainer { ); } + for (var oneof = 0; oneof < _oneofFeatures.length; oneof++) { + _oneofFeatures[oneof] = resolveFeatures( + features, + descriptor.oneofDecl[oneof].options.features, + ); + } + // Extensions within messages won't create top-level classes and don't need // to check against / be added to top-level reserved names. final usedExtensionNames = {...forbiddenExtensionNames}; @@ -237,16 +253,25 @@ class MessageGenerator extends ProtobufContainer { classname, _usedTopLevelNames, reserved: reserved, + lowercaseGroupNames: false, ); - _fieldList = []; + fieldList = []; for (final names in members.fieldNames) { - final field = ProtobufField.message(names, this, ctx); - if (field.descriptor.hasOneofIndex() && - !field.descriptor.proto3Optional) { + final descriptor = names.descriptor; + ProtobufField field; + if (descriptor.hasOneofIndex() && !descriptor.proto3Optional) { + field = ProtobufField.message( + names, + this, + _oneofFeatures[descriptor.oneofIndex], + ctx, + ); _oneofFields[field.descriptor.oneofIndex].add(field); + } else { + field = ProtobufField.message(names, this, features, ctx); } - _fieldList.add(field); + fieldList.add(field); } _oneofNames = members.oneofNames; @@ -260,7 +285,7 @@ class MessageGenerator extends ProtobufContainer { bool get needsFixnumImport { checkResolved(); - for (final field in _fieldList) { + for (final field in fieldList) { if (field.needsFixnumImport) return true; } for (final m in _messageGenerators) { @@ -281,7 +306,7 @@ class MessageGenerator extends ProtobufContainer { Set enumImports, ) { checkResolved(); - for (final field in _fieldList) { + for (final field in fieldList) { final typeGen = field.baseType.generator; if (typeGen is EnumGenerator) { enumImports.add(typeGen.fileGen!); @@ -455,7 +480,7 @@ class MessageGenerator extends ProtobufContainer { out.println('..oo($oneof, $tags)'); } - for (final field in _fieldList) { + for (final field in fieldList) { field.generateBuilderInfoCall(out, package); } @@ -520,9 +545,9 @@ class MessageGenerator extends ProtobufContainer { } void _generateFactory(IndentingWriter out) { - if (!fileGen.options.disableConstructorArgs && _fieldList.isNotEmpty) { + if (!fileGen.options.disableConstructorArgs && fieldList.isNotEmpty) { out.println('factory $classname({'); - for (final field in _fieldList) { + for (final field in fieldList) { _emitDeprecatedIf(field.isDeprecated, out); if (field.isRepeated && !field.isMapField) { out.println( @@ -543,14 +568,14 @@ class MessageGenerator extends ProtobufContainer { } out.print('}) '); - final names = _fieldList.map((f) => f.memberNames!.fieldName).toSet(); + final names = fieldList.map((f) => f.memberNames!.fieldName).toSet(); var result = 'result'; if (names.contains(result)) { result += r'$'; } out.addBlock('{', '}', () { out.println('final $result = create();'); - for (final field in _fieldList) { + for (final field in fieldList) { out.print('if (${field.memberNames!.fieldName} != null) '); if (field.isRepeated && !field.isMapField) { out.println( @@ -601,7 +626,7 @@ class MessageGenerator extends ProtobufContainer { return true; } - for (final field in type._fieldList) { + for (final field in type.fieldList) { if (field.isRequired) { return true; } @@ -620,7 +645,7 @@ class MessageGenerator extends ProtobufContainer { generateOneofAccessors(out, oneof); } - for (final field in _fieldList) { + for (final field in fieldList) { out.println(); generateFieldAccessorsMutators( field, diff --git a/protoc_plugin/lib/src/protobuf_field.dart b/protoc_plugin/lib/src/protobuf_field.dart index 8e90c810..d365d4b7 100644 --- a/protoc_plugin/lib/src/protobuf_field.dart +++ b/protoc_plugin/lib/src/protobuf_field.dart @@ -30,27 +30,47 @@ class ProtobufField { final String fullName; final BaseType baseType; final ProtobufContainer parent; + final FeatureSet features; ProtobufField.message( FieldNames names, ProtobufContainer parent, + FeatureSet inheritFeatures, GenerationContext ctx, - ) : this._(names.descriptor, names, parent, ctx); + ) : this._(names.descriptor, names, parent, inheritFeatures, ctx); ProtobufField.extension( FieldDescriptorProto descriptor, ProtobufContainer parent, GenerationContext ctx, - ) : this._(descriptor, null, parent, ctx); + ) : this._(descriptor, null, parent, parent.features, ctx); ProtobufField._( + FieldDescriptorProto descriptor, + FieldNames? dartNames, + ProtobufContainer parent, + FeatureSet inheritFeatures, + GenerationContext ctx, + ) : this._features( + descriptor, + resolveFeatures( + inheritFeatures, + _inferLegacyProtoFeatures(descriptor, parent.fileGen!.edition), + ), + dartNames, + parent, + ctx, + ); + + ProtobufField._features( this.descriptor, + this.features, FieldNames? dartNames, this.parent, GenerationContext ctx, ) : memberNames = dartNames, fullName = '${parent.fullName}.${descriptor.name}', - baseType = BaseType(descriptor, ctx); + baseType = BaseType(descriptor, features, ctx); /// The index of this field in MessageGenerator.fieldList. /// @@ -71,8 +91,9 @@ class ProtobufField { /// Whether the field is to be encoded with [deprecated = true] encoding. bool get isDeprecated => descriptor.options.deprecated; - bool get isRequired => - descriptor.label == FieldDescriptorProto_Label.LABEL_REQUIRED; + bool get isRequired { + return features.fieldPresence == FeatureSet_FieldPresence.LEGACY_REQUIRED; + } bool get isRepeated => descriptor.label == FieldDescriptorProto_Label.LABEL_REPEATED; @@ -91,20 +112,8 @@ class ProtobufField { return false; } - switch (parent.fileGen!.syntax) { - case ProtoSyntax.proto3: - if (!descriptor.hasOptions()) { - return true; // packed by default in proto3 - } else { - return !descriptor.options.hasPacked() || descriptor.options.packed; - } - case ProtoSyntax.proto2: - if (!descriptor.hasOptions()) { - return false; // not packed by default in proto3 - } else { - return descriptor.options.packed; - } - } + return features.repeatedFieldEncoding == + FeatureSet_RepeatedFieldEncoding.PACKED; } /// Whether the field has the `overrideGetter` annotation set to true. @@ -166,7 +175,7 @@ class ProtobufField { /// Only for map fields: returns the type to use for Dart map field key type. String getDartMapKeyType() { assert(isMapField); - return (baseType.generator as MessageGenerator)._fieldList[0].baseType + return (baseType.generator as MessageGenerator).fieldList[0].baseType .getDartType(parent.fileGen!); } @@ -174,7 +183,7 @@ class ProtobufField { /// type. String getDartMapValueType() { assert(isMapField); - return (baseType.generator as MessageGenerator)._fieldList[1].baseType + return (baseType.generator as MessageGenerator).fieldList[1].baseType .getDartType(parent.fileGen!); } @@ -230,8 +239,8 @@ class ProtobufField { if (isMapField) { final generator = baseType.generator as MessageGenerator; - final key = generator._fieldList[0]; - final value = generator._fieldList[1]; + final key = generator.fieldList[0]; + final value = generator.fieldList[1]; // Key type is an integer type or string. No need to specify the default // value as the library knows the defaults for integer and string fields. @@ -498,3 +507,28 @@ class ProtobufField { ); } } + +FeatureSet _inferLegacyProtoFeatures( + FieldDescriptorProto descriptor, + Edition edition, +) { + if (edition.value >= Edition.EDITION_2023.value) { + return descriptor.options.features; + } + final features = FeatureSet(); + if (descriptor.label == FieldDescriptorProto_Label.LABEL_REQUIRED) { + features.fieldPresence = FeatureSet_FieldPresence.LEGACY_REQUIRED; + } + if (descriptor.type == FieldDescriptorProto_Type.TYPE_GROUP) { + features.messageEncoding = FeatureSet_MessageEncoding.DELIMITED; + } + if (descriptor.options.packed) { + features.repeatedFieldEncoding = FeatureSet_RepeatedFieldEncoding.PACKED; + } + if (edition.value == Edition.EDITION_PROTO3.value && + descriptor.options.hasPacked() && + !descriptor.options.packed) { + features.repeatedFieldEncoding = FeatureSet_RepeatedFieldEncoding.EXPANDED; + } + return features; +} diff --git a/protoc_plugin/lib/src/service_generator.dart b/protoc_plugin/lib/src/service_generator.dart index bc26c115..7e37c217 100644 --- a/protoc_plugin/lib/src/service_generator.dart +++ b/protoc_plugin/lib/src/service_generator.dart @@ -84,7 +84,7 @@ class ServiceGenerator { mg.checkResolved(); if (depth == 0) _deps[mg.dottedName] = mg; _transitiveDeps[mg.dottedName] = mg; - for (final field in mg._fieldList) { + for (final field in mg.fieldList) { if (field.baseType.isGroup || field.baseType.isMessage) { _addDepsRecursively( field.baseType.generator as MessageGenerator, diff --git a/protoc_plugin/test/client_generator_test.dart b/protoc_plugin/test/client_generator_test.dart index 43956643..a8f27113 100644 --- a/protoc_plugin/test/client_generator_test.dart +++ b/protoc_plugin/test/client_generator_test.dart @@ -13,6 +13,7 @@ import 'package:test/test.dart'; import 'src/golden_file.dart'; import 'src/service_util.dart'; +import 'src/test_features.dart'; void main() { test('testClientGenerator', () { @@ -22,13 +23,13 @@ void main() { 'SomeReply', ]); fd.service.add(buildServiceDescriptor()); - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); final fd2 = buildFileDescriptor('foo.bar', 'foobar.proto', [ 'EmptyMessage', 'AnotherReply', ]); - final fg2 = FileGenerator(fd2, options); + final fg2 = FileGenerator(testEditionDefaults, fd2, options); link(GenerationOptions(), [fg, fg2]); diff --git a/protoc_plugin/test/enum_generator_test.dart b/protoc_plugin/test/enum_generator_test.dart index f41bd0a2..96c14a5a 100644 --- a/protoc_plugin/test/enum_generator_test.dart +++ b/protoc_plugin/test/enum_generator_test.dart @@ -12,10 +12,16 @@ import 'package:protoc_plugin/src/options.dart'; import 'package:test/test.dart'; import 'src/golden_file.dart'; +import 'src/test_features.dart'; void main() { - test('testEnumGenerator', () { - final ed = + late FileDescriptorProto fd; + late EnumDescriptorProto ed; + late DescriptorProto md; + + setUp(() async { + fd = FileDescriptorProto(); + ed = EnumDescriptorProto() ..name = 'PhoneType' ..value.addAll([ @@ -32,14 +38,58 @@ void main() { ..name = 'BUSINESS' ..number = 2, ]); + md = DescriptorProto()..enumType.add(ed); + }); + + test('testEnumGenerator', () { final writer = IndentingWriter( generateMetadata: true, fileName: 'sample.proto', ); - final fg = FileGenerator(FileDescriptorProto(), GenerationOptions()); + final fg = FileGenerator( + testEditionDefaults, + FileDescriptorProto(), + GenerationOptions(), + ); final eg = EnumGenerator.topLevel(ed, fg, {}, 0); eg.generate(writer); - expectGolden(writer.emitSource(format: false), 'enum.pbenum.dart'); - expectGolden(writer.sourceLocationInfo.toString(), 'enum.pbenum.dart.meta'); + expectGolden(writer.toString(), 'enum'); + expectGolden(writer.sourceLocationInfo.toString(), 'enum.meta'); + }); + + test('EnumGenerator inherits from a parent file', () { + setTestFeature(fd, 1); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final eg = EnumGenerator.topLevel(ed, fg, {}, 0); + + expect(getTestFeature(eg.features), 1); + }); + + test('EnumGenerator inherits from a parent message', () { + setTestFeature(md, 1); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.nested(md, fg, {}, null, {}, 0); + final eg = EnumGenerator.nested(ed, mg, {}, 0); + + expect(getTestFeature(eg.features), 1); + }); + + test('EnumGenerator can override parent file features', () { + setTestFeature(fd, 1); + setTestFeature(ed, 2); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final eg = EnumGenerator.topLevel(ed, fg, {}, 0); + + expect(getTestFeature(eg.features), 2); + }); + + test('EnumGenerator can override parent message features', () { + setTestFeature(md, 1); + setTestFeature(ed, 2); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.nested(md, fg, {}, null, {}, 0); + final eg = EnumGenerator.nested(ed, mg, {}, 0); + + expect(getTestFeature(eg.features), 2); }); } diff --git a/protoc_plugin/test/extension_generator_test.dart b/protoc_plugin/test/extension_generator_test.dart index bd3775aa..8dc805d3 100644 --- a/protoc_plugin/test/extension_generator_test.dart +++ b/protoc_plugin/test/extension_generator_test.dart @@ -15,17 +15,21 @@ import 'package:protoc_plugin/src/options.dart'; import 'package:test/test.dart'; import 'src/golden_file.dart'; +import 'src/test_features.dart'; + +pb.FieldDescriptorProto makeExtension() { + return pb.FieldDescriptorProto() + ..name = 'client_info' + ..jsonName = 'clientInfo' + ..number = 261486461 + ..label = pb.FieldDescriptorProto_Label.LABEL_OPTIONAL + ..type = pb.FieldDescriptorProto_Type.TYPE_STRING + ..extendee = '.Card'; +} void main() { test('testExtensionGenerator', () { - final extensionFieldDescriptor = - pb.FieldDescriptorProto() - ..name = 'client_info' - ..jsonName = 'clientInfo' - ..number = 261486461 - ..label = pb.FieldDescriptorProto_Label.LABEL_OPTIONAL - ..type = pb.FieldDescriptorProto_Type.TYPE_STRING - ..extendee = '.Card'; + final extensionFieldDescriptor = makeExtension(); final messageDescriptor = pb.DescriptorProto() ..name = 'Card' @@ -35,7 +39,11 @@ void main() { ..messageType.add(messageDescriptor) ..extension.add(extensionFieldDescriptor); - final fileGenerator = FileGenerator(fileDescriptor, GenerationOptions()); + final fileGenerator = FileGenerator( + testEditionDefaults, + fileDescriptor, + GenerationOptions(), + ); final options = parseGenerationOptions( pb.CodeGeneratorRequest(), pb.CodeGeneratorResponse(), @@ -47,11 +55,65 @@ void main() { ); fileGenerator.extensionGenerators.single.generate(writer); - final actual = writer.emitSource(format: false); - expectGolden(actual, 'extension.pb.dart'); - expectGolden( - writer.sourceLocationInfo.toString(), - 'extension.pb.dart.meta', + expectGolden(writer.toString(), 'extension'); + expectGolden(writer.sourceLocationInfo.toString(), 'extension.meta'); + }); + + test('ExtensionGenerator inherits from a parent file', () { + final ed = makeExtension(); + final fd = setTestFeature( + pb.FileDescriptorProto() + ..edition = pb.Edition.EDITION_2023 + ..extension.add(ed), + 1, + ); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + fg.resolve(GenerationContext(GenerationOptions())); + + expect(getTestFeature(fg.extensionGenerators.single.features), 1); + }); + + test('ExtensionGenerator can override parent file features', () { + final ed = setTestFeature(makeExtension(), 2); + final fd = setTestFeature( + pb.FileDescriptorProto() + ..edition = pb.Edition.EDITION_2023 + ..extension.add(ed), + 1, ); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + fg.resolve(GenerationContext(GenerationOptions())); + + expect(getTestFeature(fg.extensionGenerators.single.features), 2); + }); + + test('ExtensionGenerator inherits from a parent message', () { + final ed = makeExtension(); + final md = setTestFeature(pb.DescriptorProto()..extension.add(ed), 1); + final fd = + pb.FileDescriptorProto() + ..edition = pb.Edition.EDITION_2023 + ..messageType.add(md); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + final eg = ExtensionGenerator.nested(ed, mg, {}, 0); + eg.resolve(GenerationContext(GenerationOptions())); + + expect(getTestFeature(eg.features), 1); + }); + + test('ExtensionGenerator can override parent message features', () { + final ed = setTestFeature(makeExtension(), 2); + final md = setTestFeature(pb.DescriptorProto()..extension.add(ed), 1); + final fd = + pb.FileDescriptorProto() + ..edition = pb.Edition.EDITION_2023 + ..messageType.add(md); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + final eg = ExtensionGenerator.nested(ed, mg, {}, 0); + eg.resolve(GenerationContext(GenerationOptions())); + + expect(getTestFeature(eg.features), 2); }); } diff --git a/protoc_plugin/test/file_generator_test.dart b/protoc_plugin/test/file_generator_test.dart index 13b931d7..43a96826 100644 --- a/protoc_plugin/test/file_generator_test.dart +++ b/protoc_plugin/test/file_generator_test.dart @@ -15,6 +15,7 @@ import 'package:protoc_plugin/src/options.dart'; import 'package:test/test.dart'; import 'src/golden_file.dart'; +import 'src/test_features.dart'; FileDescriptorProto buildFileDescriptor({ bool phoneNumber = true, @@ -111,7 +112,7 @@ void main() { CodeGeneratorRequest()..parameter = 'disable_constructor_args', CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); expectGolden( fg.generateMainFile().emitSource(format: true), @@ -127,7 +128,7 @@ void main() { CodeGeneratorRequest()..parameter = 'disable_constructor_args', CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); expectGolden( fg.generateMainFile().emitSource(format: true), @@ -145,7 +146,7 @@ void main() { ..parameter = 'generate_kythe_info,disable_constructor_args', CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); expectGolden( fg.generateMainFile().sourceLocationInfo.toString(), @@ -163,7 +164,7 @@ void main() { CodeGeneratorRequest()..parameter = 'disable_constructor_args', CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); expectGolden(fg.generateJsonFile(), 'oneMessage.pbjson.dart'); }, @@ -177,7 +178,7 @@ void main() { CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); expectGolden( fg.generateMainFile().emitSource(format: true), @@ -197,7 +198,7 @@ void main() { ..parameter = 'generate_kythe_info,disable_constructor_args', CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); expectGolden( @@ -218,7 +219,7 @@ void main() { CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); expectGolden(fg.generateJsonFile(), 'topLevelEnum.pbjson.dart'); }); @@ -232,7 +233,7 @@ void main() { CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); final writer = IndentingWriter(); @@ -262,7 +263,7 @@ void main() { CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); final writer = IndentingWriter(); @@ -295,7 +296,7 @@ void main() { CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); final writer = IndentingWriter(); @@ -330,7 +331,7 @@ void main() { final options = GenerationOptions(useGrpc: true); - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); final writer = IndentingWriter(); @@ -427,7 +428,7 @@ void main() { final options = GenerationOptions(useGrpc: true); - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [fg]); final writer = IndentingWriter(); @@ -547,11 +548,11 @@ void main() { final response = CodeGeneratorResponse(); final options = parseGenerationOptions(request, response)!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); link(options, [ fg, - FileGenerator(fd1, options), - FileGenerator(fd2, options), + FileGenerator(testEditionDefaults, fd1, options), + FileGenerator(testEditionDefaults, fd2, options), ]); expectGolden( fg.generateMainFile().emitSource(format: true), @@ -562,4 +563,114 @@ void main() { 'imports.pbjson.dart', ); }); + + test('FileGenerator rejects files without valid edition defaults', () { + final fd = buildFileDescriptor(); + final editionDefaults = + FeatureSetDefaults() + ..defaults.add( + FeatureSetDefaults_FeatureSetEditionDefault() + ..edition = Edition.EDITION_2023 + ..overridableFeatures = + testEditionDefaults.defaults[0].overridableFeatures, + ) + ..minimumEdition = Edition.EDITION_PROTO2 + ..maximumEdition = Edition.EDITION_2023; + + expect( + () => FileGenerator(editionDefaults, fd, GenerationOptions()), + throwsA( + const TypeMatcher().having( + (e) => e.message, + 'message', + allOf(contains('No default found'), contains('EDITION_PROTO2')), + ), + ), + ); + }); + + test('FileGenerator rejects files before the minimum supported edition', () { + final fd = buildFileDescriptor(); + final editionDefaults = + FeatureSetDefaults() + ..defaults.addAll(testEditionDefaults.defaults.sublist(1)) + ..minimumEdition = Edition.EDITION_PROTO3 + ..maximumEdition = Edition.EDITION_2023; + + expect( + () => FileGenerator(editionDefaults, fd, GenerationOptions()), + throwsA( + const TypeMatcher().having( + (e) => e.message, + 'message', + contains('earlier than the minimum'), + ), + ), + ); + }); + + test('FileGenerator rejects files after the maximum supported edition', () { + final fd = buildFileDescriptor()..edition = Edition.EDITION_2023; + final editionDefaults = + FeatureSetDefaults() + ..defaults.addAll(testEditionDefaults.defaults) + ..minimumEdition = Edition.EDITION_PROTO2 + ..maximumEdition = Edition.EDITION_PROTO3; + + expect( + () => FileGenerator(editionDefaults, fd, GenerationOptions()), + throwsA( + const TypeMatcher().having( + (e) => e.message, + 'message', + contains('later than the maximum'), + ), + ), + ); + }); + + test('FileGenerator initializes the file-level edition defaults', () { + final fd = buildFileDescriptor(); + final editionDefaults = testEditionDefaults.clone(); + setTestFeature(editionDefaults.defaults[0].overridableFeatures, 1); + + final fg = FileGenerator(editionDefaults, fd, GenerationOptions()); + expect(fg.features.enumType, FeatureSet_EnumType.CLOSED); + expect(fg.features.fieldPresence, FeatureSet_FieldPresence.EXPLICIT); + expect( + fg.features.messageEncoding, + FeatureSet_MessageEncoding.LENGTH_PREFIXED, + ); + expect(fg.features.utf8Validation, FeatureSet_Utf8Validation.NONE); + expect( + fg.features.repeatedFieldEncoding, + FeatureSet_RepeatedFieldEncoding.EXPANDED, + ); + expect(fg.features.jsonFormat, FeatureSet_JsonFormat.LEGACY_BEST_EFFORT); + expect(getTestFeature(fg.features), 1); + }); + + test('FileGenerator uses file-level overrides', () { + final fd = setTestFeature( + buildFileDescriptor()..edition = Edition.EDITION_2023, + 2, + ); + final editionDefaults = testEditionDefaults.clone(); + setTestFeature(editionDefaults.defaults[0].overridableFeatures, 1); + + final fg = FileGenerator(editionDefaults, fd, GenerationOptions()); + expect(fg.features.enumType, FeatureSet_EnumType.OPEN); + expect(fg.features.fieldPresence, FeatureSet_FieldPresence.EXPLICIT); + expect( + fg.features.messageEncoding, + FeatureSet_MessageEncoding.LENGTH_PREFIXED, + ); + expect(fg.features.utf8Validation, FeatureSet_Utf8Validation.VERIFY); + expect( + fg.features.repeatedFieldEncoding, + FeatureSet_RepeatedFieldEncoding.PACKED, + ); + expect(fg.features.jsonFormat, FeatureSet_JsonFormat.ALLOW); + expect(getTestFeature(fg.features), 2); + }); } diff --git a/protoc_plugin/test/goldens/enum b/protoc_plugin/test/goldens/enum new file mode 100644 index 00000000..c804d790 --- /dev/null +++ b/protoc_plugin/test/goldens/enum @@ -0,0 +1 @@ +Instance of 'IndentingWriter' \ No newline at end of file diff --git a/protoc_plugin/test/goldens/enum.meta b/protoc_plugin/test/goldens/enum.meta new file mode 100644 index 00000000..0c5b9018 --- /dev/null +++ b/protoc_plugin/test/goldens/enum.meta @@ -0,0 +1,43 @@ +annotation: { + path: 5 + path: 0 + sourceFile: sample.proto + begin: 6 + end: 15 +} +annotation: { + path: 5 + path: 0 + path: 2 + path: 0 + sourceFile: sample.proto + begin: 68 + end: 74 +} +annotation: { + path: 5 + path: 0 + path: 2 + path: 1 + sourceFile: sample.proto + begin: 150 + end: 154 +} +annotation: { + path: 5 + path: 0 + path: 2 + path: 2 + sourceFile: sample.proto + begin: 228 + end: 232 +} +annotation: { + path: 5 + path: 0 + path: 2 + path: 3 + sourceFile: sample.proto + begin: 307 + end: 315 +} diff --git a/protoc_plugin/test/goldens/extension b/protoc_plugin/test/goldens/extension new file mode 100644 index 00000000..c804d790 --- /dev/null +++ b/protoc_plugin/test/goldens/extension @@ -0,0 +1 @@ +Instance of 'IndentingWriter' \ No newline at end of file diff --git a/protoc_plugin/test/goldens/extension.meta b/protoc_plugin/test/goldens/extension.meta new file mode 100644 index 00000000..27e35be0 --- /dev/null +++ b/protoc_plugin/test/goldens/extension.meta @@ -0,0 +1,7 @@ +annotation: { + path: 7 + path: 0 + sourceFile: sample.proto + begin: 13 + end: 23 +} diff --git a/protoc_plugin/test/import_option_test.dart b/protoc_plugin/test/import_option_test.dart new file mode 100644 index 00000000..fd7324d5 --- /dev/null +++ b/protoc_plugin/test/import_option_test.dart @@ -0,0 +1,34 @@ +// 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 'gen/custom_option.pb.dart'; +import 'gen/import_option.pbjson.dart'; +import 'package:fixnum/fixnum.dart'; +import 'package:protobuf/protobuf.dart'; +import 'package:protoc_plugin/src/gen/google/protobuf/descriptor.pb.dart'; +import 'package:test/test.dart'; + +void main() { + test('can read custom options from linked import option', () { + final registry = ExtensionRegistry()..add(Custom_option.myOption); + final descriptor = DescriptorProto.fromBuffer( + messageWithOptionsDescriptor, + registry, + ); + final option = descriptor.options.getExtension(Custom_option.myOption); + expect(option, 'Hello world!'); + }); + + test('unlinked options are in unknown fields', () { + final registry = ExtensionRegistry()..add(Custom_option.myOption); + final descriptor = DescriptorProto.fromBuffer( + messageWithOptionsDescriptor, + registry, + ); + final ufs = descriptor.options.unknownFields; + expect(ufs.hasField(51235), true); + expect(ufs.getField(51235)!.varints.length, 1); + expect(ufs.getField(51235)!.varints.first, Int64(99)); + }); +} diff --git a/protoc_plugin/test/message_generator_test.dart b/protoc_plugin/test/message_generator_test.dart index 5585e5c3..d21c15cf 100644 --- a/protoc_plugin/test/message_generator_test.dart +++ b/protoc_plugin/test/message_generator_test.dart @@ -17,6 +17,7 @@ import 'package:protoc_plugin/src/options.dart'; import 'package:test/test.dart'; import 'src/golden_file.dart'; +import 'src/test_features.dart'; void main() { late FileDescriptorProto fd; @@ -86,7 +87,7 @@ void main() { CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); final ctx = GenerationContext(options); @@ -119,7 +120,7 @@ void main() { CodeGeneratorRequest()..parameter = 'disable_constructor_args', CodeGeneratorResponse(), )!; - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); final ctx = GenerationContext(options); @@ -162,4 +163,191 @@ void main() { expect(annotatedName, isIn(expectedStrings)); } }); + + test('MessageGenerator inherits from a parent file', () { + setTestFeature(fd, 1); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + expect(getTestFeature(mg.features), 1); + }); + + test('MessageGenerator can override parent file features', () { + setTestFeature(fd, 1); + setTestFeature(md, 2); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + expect(getTestFeature(mg.features), 2); + }); + + test('MessageGenerator inherits from a parent message', () { + final mdParent = setTestFeature(md.clone(), 1); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mgParent = MessageGenerator.topLevel( + mdParent, + fg, + {}, + null, + {}, + 0, + ); + final mg = MessageGenerator.nested(md, mgParent, {}, null, {}, 0); + + expect(getTestFeature(mg.features), 1); + }); + + test('MessageGenerator can override parent message features', () { + final mdParent = setTestFeature(md.clone(), 1); + setTestFeature(md, 2); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mgParent = MessageGenerator.topLevel( + mdParent, + fg, + {}, + null, + {}, + 0, + ); + final mg = MessageGenerator.nested(md, mgParent, {}, null, {}, 0); + + expect(getTestFeature(mg.features), 2); + }); + + test('MessageGenerator fields inherit from a parent message', () { + fd.edition = Edition.EDITION_2023; + (md.field..clear()).add( + FieldDescriptorProto() + ..name = 'number' + ..jsonName = 'number' + ..number = 1 + ..label = FieldDescriptorProto_Label.LABEL_OPTIONAL + ..type = FieldDescriptorProto_Type.TYPE_STRING, + ); + setTestFeature(md, 1); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + final ctx = GenerationContext(GenerationOptions()); + mg.register(ctx); + mg.resolve(ctx); + + expect(getTestFeature(mg.fieldList[0].features), 1); + }); + + test('MessageGenerator fields can override parent message features', () { + fd.edition = Edition.EDITION_2023; + (md.field..clear()).add( + FieldDescriptorProto() + ..name = 'number' + ..jsonName = 'number' + ..number = 1 + ..label = FieldDescriptorProto_Label.LABEL_OPTIONAL + ..type = FieldDescriptorProto_Type.TYPE_STRING, + ); + setTestFeature(md, 1); + setTestFeature(md.field[0], 2); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + final ctx = GenerationContext(GenerationOptions()); + mg.register(ctx); + mg.resolve(ctx); + + expect(getTestFeature(mg.fieldList[0].features), 2); + }); + + test('MessageGenerator fields inherit from a parent oneof', () { + fd.edition = Edition.EDITION_2023; + md.oneofDecl.add(OneofDescriptorProto()..name = 'oneof'); + (md.field..clear()).add( + FieldDescriptorProto() + ..name = 'number' + ..jsonName = 'number' + ..number = 1 + ..oneofIndex = 0 + ..label = FieldDescriptorProto_Label.LABEL_OPTIONAL + ..type = FieldDescriptorProto_Type.TYPE_STRING, + ); + setTestFeature(md.oneofDecl[0], 1); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + final ctx = GenerationContext(GenerationOptions()); + mg.register(ctx); + mg.resolve(ctx); + + expect(getTestFeature(mg.fieldList[0].features), 1); + }); + + test('MessageGenerator fields can override parent oneof', () { + fd.edition = Edition.EDITION_2023; + md.oneofDecl.add(OneofDescriptorProto()..name = 'oneof'); + (md.field..clear()).add( + FieldDescriptorProto() + ..name = 'number' + ..jsonName = 'number' + ..number = 1 + ..oneofIndex = 0 + ..label = FieldDescriptorProto_Label.LABEL_OPTIONAL + ..type = FieldDescriptorProto_Type.TYPE_STRING, + ); + setTestFeature(md.oneofDecl[0], 1); + setTestFeature(md.field[0], 2); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + final ctx = GenerationContext(GenerationOptions()); + mg.register(ctx); + mg.resolve(ctx); + + expect(getTestFeature(mg.fieldList[0].features), 2); + }); + + test('MessageGenerator oneof inherits from a parent message', () { + fd.edition = Edition.EDITION_2023; + md.oneofDecl.add(OneofDescriptorProto()..name = 'oneof'); + (md.field..clear()).add( + FieldDescriptorProto() + ..name = 'number' + ..jsonName = 'number' + ..number = 1 + ..oneofIndex = 0 + ..label = FieldDescriptorProto_Label.LABEL_OPTIONAL + ..type = FieldDescriptorProto_Type.TYPE_STRING, + ); + setTestFeature(md, 1); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + final ctx = GenerationContext(GenerationOptions()); + mg.register(ctx); + mg.resolve(ctx); + + expect(getTestFeature(mg.fieldList[0].features), 1); + }); + + test('MessageGenerator oneof can override parent message', () { + fd.edition = Edition.EDITION_2023; + md.oneofDecl.add(OneofDescriptorProto()..name = 'oneof'); + (md.field..clear()).add( + FieldDescriptorProto() + ..name = 'number' + ..jsonName = 'number' + ..number = 1 + ..oneofIndex = 0 + ..label = FieldDescriptorProto_Label.LABEL_OPTIONAL + ..type = FieldDescriptorProto_Type.TYPE_STRING, + ); + setTestFeature(md, 1); + setTestFeature(md.oneofDecl[0], 2); + final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); + final mg = MessageGenerator.topLevel(md, fg, {}, null, {}, 0); + + final ctx = GenerationContext(GenerationOptions()); + mg.register(ctx); + mg.resolve(ctx); + + expect(getTestFeature(mg.fieldList[0].features), 2); + }); } diff --git a/protoc_plugin/test/protos/custom_option_unlinked.proto b/protoc_plugin/test/protos/custom_option_unlinked.proto new file mode 100644 index 00000000..46243035 --- /dev/null +++ b/protoc_plugin/test/protos/custom_option_unlinked.proto @@ -0,0 +1,15 @@ +// Copyright (c) 2020, 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. + +// This file defines an option that is not linked into the test, to verify that +// it ends up in unknown fields as expected. +syntax = "proto2"; + +package custom_option; + +import "google/protobuf/descriptor.proto"; + +extend proto2.MessageOptions { + optional int32 unlinked_option = 51235; +} diff --git a/protoc_plugin/test/protos/import_option.proto b/protoc_plugin/test/protos/import_option.proto new file mode 100644 index 00000000..b2c1d402 --- /dev/null +++ b/protoc_plugin/test/protos/import_option.proto @@ -0,0 +1,13 @@ +edition = "2024"; + +package import_option; + +import option "custom_option.proto"; +import option "custom_option_unlinked.proto"; + +message MessageWithOptions { + option (custom_option.my_option) = "Hello world!"; + option (custom_option.unlinked_option) = 99; + + string a = 1; +} diff --git a/protoc_plugin/test/src/test_features.dart b/protoc_plugin/test/src/test_features.dart new file mode 100644 index 00000000..9097b7b0 --- /dev/null +++ b/protoc_plugin/test/src/test_features.dart @@ -0,0 +1,25 @@ +import 'package:protoc_plugin/protoc.dart'; +import 'package:protoc_plugin/src/gen/google/protobuf/descriptor.pb.dart'; +import 'package:protoc_plugin/src/gen/google/protobuf/unittest_features.pb.dart'; + +final testEditionDefaults = pluginFeatureSetDefaults; + +// Sets a test-only feature extension that can be applied to any type of descriptor. +dynamic setTestFeature(dynamic descriptor, int value) { + var features = descriptor; + if (descriptor is! FeatureSet) { + descriptor.ensureOptions(); + descriptor.options.ensureFeatures(); + features = descriptor.options.features; + } + features.setExtension( + Unittest_features.test, + TestFeatures()..multipleFeature = EnumFeature.valueOf(value)!, + ); + return descriptor; +} + +// Retrieves a test-only feature extension on an arbitrary descriptor. +int getTestFeature(FeatureSet features) { + return features.getExtension(Unittest_features.test).multipleFeature.value; +} From 0abc721d0e7e6cb760fcec0a843299f073d6dc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 10:59:49 +0100 Subject: [PATCH 04/16] Fix goldens --- protoc_plugin/test/enum_generator_test.dart | 2 +- .../test/extension_generator_test.dart | 2 +- protoc_plugin/test/goldens/enum | 22 ++++++++++++++++++- protoc_plugin/test/goldens/extension | 5 ++++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/protoc_plugin/test/enum_generator_test.dart b/protoc_plugin/test/enum_generator_test.dart index 96c14a5a..a140a5d4 100644 --- a/protoc_plugin/test/enum_generator_test.dart +++ b/protoc_plugin/test/enum_generator_test.dart @@ -53,7 +53,7 @@ void main() { ); final eg = EnumGenerator.topLevel(ed, fg, {}, 0); eg.generate(writer); - expectGolden(writer.toString(), 'enum'); + expectGolden(writer.emitSource(format: false), 'enum'); expectGolden(writer.sourceLocationInfo.toString(), 'enum.meta'); }); diff --git a/protoc_plugin/test/extension_generator_test.dart b/protoc_plugin/test/extension_generator_test.dart index 8dc805d3..94535101 100644 --- a/protoc_plugin/test/extension_generator_test.dart +++ b/protoc_plugin/test/extension_generator_test.dart @@ -55,7 +55,7 @@ void main() { ); fileGenerator.extensionGenerators.single.generate(writer); - expectGolden(writer.toString(), 'extension'); + expectGolden(writer.emitSource(format: false), 'extension'); expectGolden(writer.sourceLocationInfo.toString(), 'extension.meta'); }); diff --git a/protoc_plugin/test/goldens/enum b/protoc_plugin/test/goldens/enum index c804d790..809bfedf 100644 --- a/protoc_plugin/test/goldens/enum +++ b/protoc_plugin/test/goldens/enum @@ -1 +1,21 @@ -Instance of 'IndentingWriter' \ No newline at end of file +class PhoneType extends $pb.ProtobufEnum { + static const PhoneType MOBILE = PhoneType._(0, _omitEnumNames ? '' : 'MOBILE'); + static const PhoneType HOME = PhoneType._(1, _omitEnumNames ? '' : 'HOME'); + static const PhoneType WORK = PhoneType._(2, _omitEnumNames ? '' : 'WORK'); + + static const PhoneType BUSINESS = WORK; + + static const $core.List values = [ + MOBILE, + HOME, + WORK, + ]; + + static final $core.List _byValue = $pb.ProtobufEnum.$_initByValueList(values, 2); + static PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const PhoneType._(super.value, super.name); +} + + +const $core.bool _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/protoc_plugin/test/goldens/extension b/protoc_plugin/test/goldens/extension index c804d790..32a5dcb7 100644 --- a/protoc_plugin/test/goldens/extension +++ b/protoc_plugin/test/goldens/extension @@ -1 +1,4 @@ -Instance of 'IndentingWriter' \ No newline at end of file +static final clientInfo = $pb.Extension<$core.String>(_omitMessageNames ? '' : 'Card', _omitFieldNames ? '' : 'clientInfo', 261486461, $pb.PbFieldType.OS); + +const $core.bool _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); +const $core.bool _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); From 3dd51265ffcc10b8e36c65f5dd5163e2219171c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 11:05:37 +0100 Subject: [PATCH 05/16] Fixups --- protoc_plugin/test/protos/custom_option_unlinked.proto | 2 +- protoc_plugin/test/service_generator_test.dart | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/protoc_plugin/test/protos/custom_option_unlinked.proto b/protoc_plugin/test/protos/custom_option_unlinked.proto index 46243035..2ab39f6e 100644 --- a/protoc_plugin/test/protos/custom_option_unlinked.proto +++ b/protoc_plugin/test/protos/custom_option_unlinked.proto @@ -10,6 +10,6 @@ package custom_option; import "google/protobuf/descriptor.proto"; -extend proto2.MessageOptions { +extend google.protobuf.MessageOptions { optional int32 unlinked_option = 51235; } diff --git a/protoc_plugin/test/service_generator_test.dart b/protoc_plugin/test/service_generator_test.dart index 52c2401c..ca3b8a1a 100644 --- a/protoc_plugin/test/service_generator_test.dart +++ b/protoc_plugin/test/service_generator_test.dart @@ -13,6 +13,7 @@ import 'package:test/test.dart'; import 'src/golden_file.dart'; import 'src/service_util.dart'; +import 'src/test_features.dart'; void main() { test('testServiceGenerator', () { @@ -22,13 +23,13 @@ void main() { 'SomeReply', ]); fd.service.add(buildServiceDescriptor()); - final fg = FileGenerator(fd, options); + final fg = FileGenerator(testEditionDefaults, fd, options); final fd2 = buildFileDescriptor('foo.bar', 'foobar.proto', [ 'EmptyMessage', 'AnotherReply', ]); - final fg2 = FileGenerator(fd2, options); + final fg2 = FileGenerator(testEditionDefaults, fd2, options); link(GenerationOptions(), [fg, fg2]); From fb12298cf36d5eff7f08fd3c28963160e93026f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 11:07:07 +0100 Subject: [PATCH 06/16] Bump protoc version --- tool/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/setup.sh b/tool/setup.sh index 16e7b9cd..b20a1491 100755 --- a/tool/setup.sh +++ b/tool/setup.sh @@ -1,7 +1,7 @@ #!/bin/bash wget -O protoc.zip \ - https://github.com/protocolbuffers/protobuf/releases/download/v31.0/protoc-31.0-linux-x86_64.zip + https://github.com/protocolbuffers/protobuf/releases/download/v32.1/protoc-32.1-linux-x86_64.zip unzip -d protoc protoc.zip if [[ -z "${GITHUB_ENV}" ]]; then From 1d384864c3208b43d6ab47f579a64705da0cbc76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 11:10:19 +0100 Subject: [PATCH 07/16] Warns --- protoc_plugin/lib/src/file_generator.dart | 4 ++-- protoc_plugin/test/message_generator_test.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/protoc_plugin/lib/src/file_generator.dart b/protoc_plugin/lib/src/file_generator.dart index 8cba0c49..261cf6aa 100644 --- a/protoc_plugin/lib/src/file_generator.dart +++ b/protoc_plugin/lib/src/file_generator.dart @@ -841,7 +841,7 @@ Edition _getEdition(FileDescriptorProto file) { } FeatureSet resolveFeatures(FeatureSet parent, FeatureSet child) { - final result = parent.clone(); + final result = parent.deepCopy(); result.mergeFromMessage(child); return result; } @@ -870,7 +870,7 @@ FeatureSet _getEditionDefaults( if (found == null) { throw ArgumentError('No default found for edition $edition!'); } - final defaults = found.fixedFeatures.clone(); + final defaults = found.fixedFeatures.deepCopy(); defaults.mergeFromMessage(found.overridableFeatures); return defaults; } diff --git a/protoc_plugin/test/message_generator_test.dart b/protoc_plugin/test/message_generator_test.dart index d21c15cf..782cb786 100644 --- a/protoc_plugin/test/message_generator_test.dart +++ b/protoc_plugin/test/message_generator_test.dart @@ -182,7 +182,7 @@ void main() { }); test('MessageGenerator inherits from a parent message', () { - final mdParent = setTestFeature(md.clone(), 1); + final mdParent = setTestFeature(md.deepCopy(), 1); final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); final mgParent = MessageGenerator.topLevel( mdParent, @@ -198,7 +198,7 @@ void main() { }); test('MessageGenerator can override parent message features', () { - final mdParent = setTestFeature(md.clone(), 1); + final mdParent = setTestFeature(md.deepCopy(), 1); setTestFeature(md, 2); final fg = FileGenerator(testEditionDefaults, fd, GenerationOptions()); final mgParent = MessageGenerator.topLevel( From e8a58f49578eb923b18f62c8ce94519f41231e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 11:11:29 +0100 Subject: [PATCH 08/16] Warns --- protoc_plugin/test/file_generator_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protoc_plugin/test/file_generator_test.dart b/protoc_plugin/test/file_generator_test.dart index 43a96826..618209a7 100644 --- a/protoc_plugin/test/file_generator_test.dart +++ b/protoc_plugin/test/file_generator_test.dart @@ -631,7 +631,7 @@ void main() { test('FileGenerator initializes the file-level edition defaults', () { final fd = buildFileDescriptor(); - final editionDefaults = testEditionDefaults.clone(); + final editionDefaults = testEditionDefaults.deepCopy(); setTestFeature(editionDefaults.defaults[0].overridableFeatures, 1); final fg = FileGenerator(editionDefaults, fd, GenerationOptions()); @@ -655,7 +655,7 @@ void main() { buildFileDescriptor()..edition = Edition.EDITION_2023, 2, ); - final editionDefaults = testEditionDefaults.clone(); + final editionDefaults = testEditionDefaults.deepCopy(); setTestFeature(editionDefaults.defaults[0].overridableFeatures, 1); final fg = FileGenerator(editionDefaults, fd, GenerationOptions()); From 31e1731e375d4420211ce44057549b45229bfdd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 16 Sep 2025 11:33:42 +0100 Subject: [PATCH 09/16] Changelog --- protoc_plugin/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/protoc_plugin/CHANGELOG.md b/protoc_plugin/CHANGELOG.md index 504601c6..1c1a8ab5 100644 --- a/protoc_plugin/CHANGELOG.md +++ b/protoc_plugin/CHANGELOG.md @@ -6,9 +6,11 @@ Note: this version requires protobuf 5.0.0. * Update generated `clone` members to take advantage of faster `deepCopy` implementation in protobuf 5.0.0. ([#742]) * Code size improvements for enum fields. ([#1047]) +* Support protobuf editions. ([#1052]) [#742]: https://github.com/google/protobuf.dart/pull/742 [#1047]: https://github.com/google/protobuf.dart/pull/1047 +[#1052]: https://github.com/google/protobuf.dart/pull/1052 ## 22.5.0 From b8db154bf1c1ac533e4cfa3d92f4a44bf80904b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Wed, 17 Sep 2025 09:27:54 +0100 Subject: [PATCH 10/16] Update edition defaults location --- protoc_plugin/lib/protoc.dart | 6 ++---- .../gen/google/protobuf/dart_edition_defaults.pb.dart | 9 +++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100755 protoc_plugin/lib/src/gen/google/protobuf/dart_edition_defaults.pb.dart diff --git a/protoc_plugin/lib/protoc.dart b/protoc_plugin/lib/protoc.dart index 4a7d156b..3773befe 100644 --- a/protoc_plugin/lib/protoc.dart +++ b/protoc_plugin/lib/protoc.dart @@ -15,6 +15,7 @@ import 'src/gen/dart_options.pb.dart'; import 'src/gen/google/api/client.pb.dart'; import 'src/gen/google/protobuf/compiler/plugin.pb.dart'; import 'src/gen/google/protobuf/descriptor.pb.dart'; +import 'src/gen/google/protobuf/dart_edition_defaults.pb.dart'; import 'src/linker.dart'; import 'src/options.dart'; import 'src/output_config.dart'; @@ -35,9 +36,6 @@ part 'src/protobuf_field.dart'; part 'src/service_generator.dart'; part 'src/well_known_types.dart'; -const _protobufInternalDartEditionDefaults = - 'ChcYhAciACoQCAEQAhgCIAMoATACOAJAAQoXGOcHIgAqEAgCEAEYASACKAEwATgCQAEKFxjoByIMCAEQARgBIAIoATABKgQ4AkABChcY6QciEAgBEAEYASACKAEwATgBQAIqACDmByjpBw=='; - FeatureSetDefaults pluginFeatureSetDefaults = FeatureSetDefaults.fromBuffer( - base64Decode(_protobufInternalDartEditionDefaults), + base64Decode(ProtobufInternalDartEditionDefaults), ); diff --git a/protoc_plugin/lib/src/gen/google/protobuf/dart_edition_defaults.pb.dart b/protoc_plugin/lib/src/gen/google/protobuf/dart_edition_defaults.pb.dart new file mode 100755 index 00000000..25306d19 --- /dev/null +++ b/protoc_plugin/lib/src/gen/google/protobuf/dart_edition_defaults.pb.dart @@ -0,0 +1,9 @@ +// Generated with third_party/dart/protoc_plugin/tool/regenerate.sh. +// Copyright (c) 2013, 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. + +// ignore_for_file: constant_identifier_names + +const ProtobufInternalDartEditionDefaults = + 'ChcYhAciACoQCAEQAhgCIAMoATACOAJAAQoXGOcHIgAqEAgCEAEYASACKAEwATgCQAEKFxjoByIMCAEQARgBIAIoATABKgQ4AkABChcY6QciEAgBEAEYASACKAEwATgBQAIqACDmByjpBw=='; From 2640a46335d5f392bfb242d2ce119ab6748f677b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 23 Sep 2025 11:35:38 +0100 Subject: [PATCH 11/16] Check that edition support assumptions are in sync --- protoc_plugin/lib/protoc.dart | 29 ++++++++++++++++++++--- protoc_plugin/lib/src/code_generator.dart | 18 +++++++------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/protoc_plugin/lib/protoc.dart b/protoc_plugin/lib/protoc.dart index 3773befe..8ef232e9 100644 --- a/protoc_plugin/lib/protoc.dart +++ b/protoc_plugin/lib/protoc.dart @@ -36,6 +36,29 @@ part 'src/protobuf_field.dart'; part 'src/service_generator.dart'; part 'src/well_known_types.dart'; -FeatureSetDefaults pluginFeatureSetDefaults = FeatureSetDefaults.fromBuffer( - base64Decode(ProtobufInternalDartEditionDefaults), -); +final FeatureSetDefaults pluginFeatureSetDefaults = + FeatureSetDefaults.fromBuffer( + base64Decode(ProtobufInternalDartEditionDefaults), + ); + +int get pluginMinSupportedEdition { + final minSupportedEdition = Edition.EDITION_PROTO2; + + // The edition defaults should always stay synchronized with the supported + // edition range we report to protoc. It's not clear that the BUILD file + // definitions are load-bearing though, so we explicitly set them above and + // assert that the two are equal. + assert(minSupportedEdition == pluginFeatureSetDefaults.minimumEdition); + + return Edition.EDITION_PROTO2.value; +} + +int get pluginMaxSupportedEdition { + final maxSupportedEdition = Edition.EDITION_2024; + + // Same as above, check that the plugin support is in sync with the feature + // set defaults constant. + assert(maxSupportedEdition == pluginFeatureSetDefaults.minimumEdition); + + return maxSupportedEdition.value; +} diff --git a/protoc_plugin/lib/src/code_generator.dart b/protoc_plugin/lib/src/code_generator.dart index 6bb90c53..3f1ddc82 100644 --- a/protoc_plugin/lib/src/code_generator.dart +++ b/protoc_plugin/lib/src/code_generator.dart @@ -10,7 +10,12 @@ import 'package:fixnum/fixnum.dart'; import 'package:protobuf/protobuf.dart'; import '../names.dart' show lowerCaseFirstLetter; -import '../protoc.dart' show FileGenerator, pluginFeatureSetDefaults; +import '../protoc.dart' + show + FileGenerator, + pluginFeatureSetDefaults, + pluginMinSupportedEdition, + pluginMaxSupportedEdition; import 'gen/dart_options.pb.dart'; import 'gen/google/api/client.pb.dart'; import 'gen/google/protobuf/compiler/plugin.pb.dart'; @@ -137,15 +142,8 @@ class CodeGenerator { response.supportedFeatures = Int64(CodeGeneratorResponse_Feature.FEATURE_PROTO3_OPTIONAL.value) | Int64(CodeGeneratorResponse_Feature.FEATURE_SUPPORTS_EDITIONS.value); - response.minimumEdition = Edition.EDITION_PROTO2.value; - response.maximumEdition = Edition.EDITION_2024.value; - - // The edition defaults should always stay synchronized with the - // supported edition range we report to protoc. It's not clear that - // the BUILD file definitions are load-bearing though, so we - // explicitly set them above and assert that the two are equal. - assert(response.minimumEdition == editionDefaults.minimumEdition.value); - assert(response.maximumEdition == editionDefaults.maximumEdition.value); + response.minimumEdition = pluginMinSupportedEdition; + response.maximumEdition = pluginMaxSupportedEdition; _streamOut.add(response.writeToBuffer()); } From 2332be7f74c9006fa535768279d9cf0345f67561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 23 Sep 2025 11:37:17 +0100 Subject: [PATCH 12/16] Add copyright lines --- protoc_plugin/test/src/test_features.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protoc_plugin/test/src/test_features.dart b/protoc_plugin/test/src/test_features.dart index 9097b7b0..71062586 100644 --- a/protoc_plugin/test/src/test_features.dart +++ b/protoc_plugin/test/src/test_features.dart @@ -1,3 +1,7 @@ +// Copyright (c) 2025, 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:protoc_plugin/protoc.dart'; import 'package:protoc_plugin/src/gen/google/protobuf/descriptor.pb.dart'; import 'package:protoc_plugin/src/gen/google/protobuf/unittest_features.pb.dart'; From e07365e135a512c90cd4f18e298f8310a2b1fad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 23 Sep 2025 11:51:31 +0100 Subject: [PATCH 13/16] Revert golden paths --- protoc_plugin/test/enum_generator_test.dart | 4 ++-- protoc_plugin/test/extension_generator_test.dart | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/protoc_plugin/test/enum_generator_test.dart b/protoc_plugin/test/enum_generator_test.dart index a140a5d4..894e0ece 100644 --- a/protoc_plugin/test/enum_generator_test.dart +++ b/protoc_plugin/test/enum_generator_test.dart @@ -53,8 +53,8 @@ void main() { ); final eg = EnumGenerator.topLevel(ed, fg, {}, 0); eg.generate(writer); - expectGolden(writer.emitSource(format: false), 'enum'); - expectGolden(writer.sourceLocationInfo.toString(), 'enum.meta'); + expectGolden(writer.emitSource(format: false), 'enum.pbenum.dart'); + expectGolden(writer.sourceLocationInfo.toString(), 'enum.pbenum.dart.meta'); }); test('EnumGenerator inherits from a parent file', () { diff --git a/protoc_plugin/test/extension_generator_test.dart b/protoc_plugin/test/extension_generator_test.dart index 94535101..1070d7e7 100644 --- a/protoc_plugin/test/extension_generator_test.dart +++ b/protoc_plugin/test/extension_generator_test.dart @@ -55,8 +55,11 @@ void main() { ); fileGenerator.extensionGenerators.single.generate(writer); - expectGolden(writer.emitSource(format: false), 'extension'); - expectGolden(writer.sourceLocationInfo.toString(), 'extension.meta'); + expectGolden(writer.emitSource(format: false), 'extension.pb.dart'); + expectGolden( + writer.sourceLocationInfo.toString(), + 'extension.pb.dart.meta', + ); }); test('ExtensionGenerator inherits from a parent file', () { From e9420fe002c3ef5b342e71965c71911f687d73f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 23 Sep 2025 11:58:09 +0100 Subject: [PATCH 14/16] Move changelog entry uppp --- protoc_plugin/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protoc_plugin/CHANGELOG.md b/protoc_plugin/CHANGELOG.md index 1c1a8ab5..9dd89140 100644 --- a/protoc_plugin/CHANGELOG.md +++ b/protoc_plugin/CHANGELOG.md @@ -2,11 +2,11 @@ Note: this version requires protobuf 5.0.0. +* Support protobuf editions. ([#1052]) * Update generated code for protobuf 5.0.0. * Update generated `clone` members to take advantage of faster `deepCopy` implementation in protobuf 5.0.0. ([#742]) * Code size improvements for enum fields. ([#1047]) -* Support protobuf editions. ([#1052]) [#742]: https://github.com/google/protobuf.dart/pull/742 [#1047]: https://github.com/google/protobuf.dart/pull/1047 From 800df7be719daf856be54795a5724a23920387f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Tue, 23 Sep 2025 11:59:34 +0100 Subject: [PATCH 15/16] Remove unused goldens --- protoc_plugin/test/goldens/enum | 21 ----------- protoc_plugin/test/goldens/enum.meta | 43 ----------------------- protoc_plugin/test/goldens/extension | 4 --- protoc_plugin/test/goldens/extension.meta | 7 ---- 4 files changed, 75 deletions(-) delete mode 100644 protoc_plugin/test/goldens/enum delete mode 100644 protoc_plugin/test/goldens/enum.meta delete mode 100644 protoc_plugin/test/goldens/extension delete mode 100644 protoc_plugin/test/goldens/extension.meta diff --git a/protoc_plugin/test/goldens/enum b/protoc_plugin/test/goldens/enum deleted file mode 100644 index 809bfedf..00000000 --- a/protoc_plugin/test/goldens/enum +++ /dev/null @@ -1,21 +0,0 @@ -class PhoneType extends $pb.ProtobufEnum { - static const PhoneType MOBILE = PhoneType._(0, _omitEnumNames ? '' : 'MOBILE'); - static const PhoneType HOME = PhoneType._(1, _omitEnumNames ? '' : 'HOME'); - static const PhoneType WORK = PhoneType._(2, _omitEnumNames ? '' : 'WORK'); - - static const PhoneType BUSINESS = WORK; - - static const $core.List values = [ - MOBILE, - HOME, - WORK, - ]; - - static final $core.List _byValue = $pb.ProtobufEnum.$_initByValueList(values, 2); - static PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value]; - - const PhoneType._(super.value, super.name); -} - - -const $core.bool _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/protoc_plugin/test/goldens/enum.meta b/protoc_plugin/test/goldens/enum.meta deleted file mode 100644 index 0c5b9018..00000000 --- a/protoc_plugin/test/goldens/enum.meta +++ /dev/null @@ -1,43 +0,0 @@ -annotation: { - path: 5 - path: 0 - sourceFile: sample.proto - begin: 6 - end: 15 -} -annotation: { - path: 5 - path: 0 - path: 2 - path: 0 - sourceFile: sample.proto - begin: 68 - end: 74 -} -annotation: { - path: 5 - path: 0 - path: 2 - path: 1 - sourceFile: sample.proto - begin: 150 - end: 154 -} -annotation: { - path: 5 - path: 0 - path: 2 - path: 2 - sourceFile: sample.proto - begin: 228 - end: 232 -} -annotation: { - path: 5 - path: 0 - path: 2 - path: 3 - sourceFile: sample.proto - begin: 307 - end: 315 -} diff --git a/protoc_plugin/test/goldens/extension b/protoc_plugin/test/goldens/extension deleted file mode 100644 index 32a5dcb7..00000000 --- a/protoc_plugin/test/goldens/extension +++ /dev/null @@ -1,4 +0,0 @@ -static final clientInfo = $pb.Extension<$core.String>(_omitMessageNames ? '' : 'Card', _omitFieldNames ? '' : 'clientInfo', 261486461, $pb.PbFieldType.OS); - -const $core.bool _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const $core.bool _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/protoc_plugin/test/goldens/extension.meta b/protoc_plugin/test/goldens/extension.meta deleted file mode 100644 index 27e35be0..00000000 --- a/protoc_plugin/test/goldens/extension.meta +++ /dev/null @@ -1,7 +0,0 @@ -annotation: { - path: 7 - path: 0 - sourceFile: sample.proto - begin: 13 - end: 23 -} From ecab2e719ede88ae6e3a55716a26b1f9e3ea50ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20A=C4=9Facan?= Date: Wed, 24 Sep 2025 09:49:36 +0100 Subject: [PATCH 16/16] Move min/max support checks to a test --- protoc_plugin/lib/protoc.dart | 22 ++----------------- protoc_plugin/lib/src/code_generator.dart | 4 ++-- .../test/feature_set_defaults_test.dart | 16 ++++++++++++++ 3 files changed, 20 insertions(+), 22 deletions(-) create mode 100644 protoc_plugin/test/feature_set_defaults_test.dart diff --git a/protoc_plugin/lib/protoc.dart b/protoc_plugin/lib/protoc.dart index 8ef232e9..88413523 100644 --- a/protoc_plugin/lib/protoc.dart +++ b/protoc_plugin/lib/protoc.dart @@ -41,24 +41,6 @@ final FeatureSetDefaults pluginFeatureSetDefaults = base64Decode(ProtobufInternalDartEditionDefaults), ); -int get pluginMinSupportedEdition { - final minSupportedEdition = Edition.EDITION_PROTO2; +const Edition pluginMinSupportedEdition = Edition.EDITION_PROTO2; - // The edition defaults should always stay synchronized with the supported - // edition range we report to protoc. It's not clear that the BUILD file - // definitions are load-bearing though, so we explicitly set them above and - // assert that the two are equal. - assert(minSupportedEdition == pluginFeatureSetDefaults.minimumEdition); - - return Edition.EDITION_PROTO2.value; -} - -int get pluginMaxSupportedEdition { - final maxSupportedEdition = Edition.EDITION_2024; - - // Same as above, check that the plugin support is in sync with the feature - // set defaults constant. - assert(maxSupportedEdition == pluginFeatureSetDefaults.minimumEdition); - - return maxSupportedEdition.value; -} +const Edition pluginMaxSupportedEdition = Edition.EDITION_2024; diff --git a/protoc_plugin/lib/src/code_generator.dart b/protoc_plugin/lib/src/code_generator.dart index 3f1ddc82..fbcbefc3 100644 --- a/protoc_plugin/lib/src/code_generator.dart +++ b/protoc_plugin/lib/src/code_generator.dart @@ -142,8 +142,8 @@ class CodeGenerator { response.supportedFeatures = Int64(CodeGeneratorResponse_Feature.FEATURE_PROTO3_OPTIONAL.value) | Int64(CodeGeneratorResponse_Feature.FEATURE_SUPPORTS_EDITIONS.value); - response.minimumEdition = pluginMinSupportedEdition; - response.maximumEdition = pluginMaxSupportedEdition; + response.minimumEdition = pluginMinSupportedEdition.value; + response.maximumEdition = pluginMaxSupportedEdition.value; _streamOut.add(response.writeToBuffer()); } diff --git a/protoc_plugin/test/feature_set_defaults_test.dart b/protoc_plugin/test/feature_set_defaults_test.dart new file mode 100644 index 00000000..29a6a13b --- /dev/null +++ b/protoc_plugin/test/feature_set_defaults_test.dart @@ -0,0 +1,16 @@ +// Copyright (c) 2025, 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:protoc_plugin/protoc.dart'; +import 'package:test/test.dart'; + +void main() { + // The edition defaults should always stay synchronized with the supported + // edition range we report to protoc. It's not clear that the BUILD file + // definitions are load-bearing though, so we test them here. + test('Plugin supported editions are in sync with the defaults constant', () { + expect(pluginMinSupportedEdition, pluginFeatureSetDefaults.minimumEdition); + expect(pluginMaxSupportedEdition, pluginFeatureSetDefaults.maximumEdition); + }); +}