Repository: googleapis/google-cloud-rust
Pull request #1762: refactor(generator/dart): adjust concatenated names for generated classes
Author: login: devoncarew
Created: 2025-04-09T21:27:52Z | Merged: 2025-04-11T16:00:48Z

This PR:

- changes how we concatenate message and enum names into the generated dart class names
- addresses https://github.com/googleapis/google-cloud-rust/issues/1565

---

Currently, nested messages and enums are generated as:

- `MessageFoo$MessageBar`
- `MessageFoo$EnumBaz`
- `MessageFoo$MessageBar$EnumQux`

A possible change is for sub-messages to concatenate with underscores and nested enums to directly concatenate to their parent message (no concatenation char). This looks like:

- `MessageFoo_MessageBar`
- `MessageFooEnumBaz`
- `MessageFoo_MessageBarEnumQux`

This is going off the rough thinking that:

- underscores look better in the generated names than dollar signs
- enums are ~strongly owned by their parents, and often have short names (like `Type`, `Action`, or `State`)

We can change the names very easily at this point. It'll get much harder once we ship actual versions of these packages. If we keep the dollar sign conatenation for enums, that would look like:

- `MessageFoo_MessageBar`
- `MessageFoo$EnumBaz`
- `MessageFoo_MessageBar$EnumQux`

which I might actually prefer, because then you can easily see that the `EnumQux` enum is owned by the `MessageFoo_MessageBar` message.



Diff:
diff --git a/generator/dart/examples/bin/language_api.dart b/generator/dart/examples/bin/language_api.dart
index d080faa214..54733cc0ed 100644
--- a/generator/dart/examples/bin/language_api.dart
+++ b/generator/dart/examples/bin/language_api.dart
@@ -35,7 +35,7 @@ void main(List<String> args) async {
   final service = LanguageService(client: client);
   final document = Document(
     content: 'Hello, world!',
-    type: Document$Type.plainText,
+    type: Document_Type.plainText,
   );
 
   try {
diff --git a/generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart b/generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
index 12724d32b6..1af9644d85 100755
--- a/generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
+++ b/generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
@@ -224,7 +224,7 @@ class Function$ extends Message {
   final EventTrigger? eventTrigger;
 
   /// Output only. State of the function.
-  final Function$$State? state;
+  final Function$_State? state;
 
   /// Output only. The last update timestamp of a Cloud Function.
   final Timestamp? updateTime;
@@ -279,7 +279,7 @@ class Function$ extends Message {
       buildConfig: decode(json['buildConfig'], BuildConfig.fromJson),
       serviceConfig: decode(json['serviceConfig'], ServiceConfig.fromJson),
       eventTrigger: decode(json['eventTrigger'], EventTrigger.fromJson),
-      state: decode(json['state'], Function$$State.fromJson),
+      state: decode(json['state'], Function$_State.fromJson),
       updateTime: decode(json['updateTime'], Timestamp.fromJson),
       labels: (json['labels'] as Map?)?.cast(),
       stateMessages: decodeList(json['stateMessages'], StateMessage.fromJson),
@@ -327,33 +327,33 @@ class Function$ extends Message {
 }
 
 /// Describes the current state of the function.
-class Function$$State extends Enum {
+class Function$_State extends Enum {
   /// Not specified. Invalid state.
-  static const stateUnspecified = Function$$State('STATE_UNSPECIFIED');
+  static const stateUnspecified = Function$_State('STATE_UNSPECIFIED');
 
   /// Function has been successfully deployed and is serving.
-  static const active = Function$$State('ACTIVE');
+  static const active = Function$_State('ACTIVE');
 
   /// Function deployment failed and the function is not serving.
-  static const failed = Function$$State('FAILED');
+  static const failed = Function$_State('FAILED');
 
   /// Function is being created or updated.
-  static const deploying = Function$$State('DEPLOYING');
+  static const deploying = Function$_State('DEPLOYING');
 
   /// Function is being deleted.
-  static const deleting = Function$$State('DELETING');
+  static const deleting = Function$_State('DELETING');
 
   /// Function deployment failed and the function serving state is undefined.
   /// The function should be updated or deleted to move it out of this state.
-  static const unknown = Function$$State('UNKNOWN');
+  static const unknown = Function$_State('UNKNOWN');
 
-  const Function$$State(super.value);
+  const Function$_State(super.value);
 
-  factory Function$$State.fromJson(String json) => Function$$State(json);
+  factory Function$_State.fromJson(String json) => Function$_State(json);
 
   @override
   bool operator ==(Object other) =>
-      other is Function$$State && value == other.value;
+      other is Function$_State && value == other.value;
 
   @override
   String toString() => 'State.$value';
@@ -365,7 +365,7 @@ class StateMessage extends Message {
       'google.cloud.functions.v2.StateMessage';
 
   /// Severity of the state message.
-  final StateMessage$Severity? severity;
+  final StateMessage_Severity? severity;
 
   /// One-word CamelCase type of the state message.
   final String? type;
@@ -381,7 +381,7 @@ class StateMessage extends Message {
 
   factory StateMessage.fromJson(Map<String, dynamic> json) {
     return StateMessage(
-      severity: decode(json['severity'], StateMessage$Severity.fromJson),
+      severity: decode(json['severity'], StateMessage_Severity.fromJson),
       type: json['type'],
       message: json['message'],
     );
@@ -408,28 +408,28 @@ class StateMessage extends Message {
 }
 
 /// Severity of the state message.
-class StateMessage$Severity extends Enum {
+class StateMessage_Severity extends Enum {
   /// Not specified. Invalid severity.
   static const severityUnspecified =
-      StateMessage$Severity('SEVERITY_UNSPECIFIED');
+      StateMessage_Severity('SEVERITY_UNSPECIFIED');
 
   /// ERROR-level severity.
-  static const error = StateMessage$Severity('ERROR');
+  static const error = StateMessage_Severity('ERROR');
 
   /// WARNING-level severity.
-  static const warning = StateMessage$Severity('WARNING');
+  static const warning = StateMessage_Severity('WARNING');
 
   /// INFO-level severity.
-  static const info = StateMessage$Severity('INFO');
+  static const info = StateMessage_Severity('INFO');
 
-  const StateMessage$Severity(super.value);
+  const StateMessage_Severity(super.value);
 
-  factory StateMessage$Severity.fromJson(String json) =>
-      StateMessage$Severity(json);
+  factory StateMessage_Severity.fromJson(String json) =>
+      StateMessage_Severity(json);
 
   @override
   bool operator ==(Object other) =>
-      other is StateMessage$Severity && value == other.value;
+      other is StateMessage_Severity && value == other.value;
 
   @override
   String toString() => 'Severity.$value';
@@ -751,7 +751,7 @@ class BuildConfig extends Message {
   /// If unspecified, it defaults to `ARTIFACT_REGISTRY`.
   /// If `docker_repository` field is specified, this field should either be left
   /// unspecified or set to `ARTIFACT_REGISTRY`.
-  final BuildConfig$DockerRegistry? dockerRegistry;
+  final BuildConfig_DockerRegistry? dockerRegistry;
 
   /// Repository in Artifact Registry to which the function docker image will be
   /// pushed after it is built by Cloud Build. If specified by user, it is
@@ -798,7 +798,7 @@ class BuildConfig extends Message {
       workerPool: json['workerPool'],
       environmentVariables: (json['environmentVariables'] as Map?)?.cast(),
       dockerRegistry:
-          decode(json['dockerRegistry'], BuildConfig$DockerRegistry.fromJson),
+          decode(json['dockerRegistry'], BuildConfig_DockerRegistry.fromJson),
       dockerRepository: json['dockerRepository'],
       serviceAccount: json['serviceAccount'],
     );
@@ -842,15 +842,15 @@ class BuildConfig extends Message {
 }
 
 /// Docker Registry to use for storing function Docker images.
-class BuildConfig$DockerRegistry extends Enum {
+class BuildConfig_DockerRegistry extends Enum {
   /// Unspecified.
   static const dockerRegistryUnspecified =
-      BuildConfig$DockerRegistry('DOCKER_REGISTRY_UNSPECIFIED');
+      BuildConfig_DockerRegistry('DOCKER_REGISTRY_UNSPECIFIED');
 
   /// Docker images will be stored in multi-regional Container Registry
   /// repositories named `gcf`.
   static const containerRegistry =
-      BuildConfig$DockerRegistry('CONTAINER_REGISTRY');
+      BuildConfig_DockerRegistry('CONTAINER_REGISTRY');
 
   /// Docker images will be stored in regional Artifact Registry repositories.
   /// By default, GCF will create and use repositories named `gcf-artifacts`
@@ -858,16 +858,16 @@ class BuildConfig$DockerRegistry extends Enum {
   /// use can also be specified by the user using the `docker_repository`
   /// field.
   static const artifactRegistry =
-      BuildConfig$DockerRegistry('ARTIFACT_REGISTRY');
+      BuildConfig_DockerRegistry('ARTIFACT_REGISTRY');
 
-  const BuildConfig$DockerRegistry(super.value);
+  const BuildConfig_DockerRegistry(super.value);
 
-  factory BuildConfig$DockerRegistry.fromJson(String json) =>
-      BuildConfig$DockerRegistry(json);
+  factory BuildConfig_DockerRegistry.fromJson(String json) =>
+      BuildConfig_DockerRegistry(json);
 
   @override
   bool operator ==(Object other) =>
-      other is BuildConfig$DockerRegistry && value == other.value;
+      other is BuildConfig_DockerRegistry && value == other.value;
 
   @override
   String toString() => 'DockerRegistry.$value';
@@ -938,11 +938,11 @@ class ServiceConfig extends Message {
 
   /// The egress settings for the connector, controlling what traffic is diverted
   /// through it.
-  final ServiceConfig$VpcConnectorEgressSettings? vpcConnectorEgressSettings;
+  final ServiceConfig_VpcConnectorEgressSettings? vpcConnectorEgressSettings;
 
   /// The ingress settings for the function, controlling what traffic can reach
   /// it.
-  final ServiceConfig$IngressSettings? ingressSettings;
+  final ServiceConfig_IngressSettings? ingressSettings;
 
   /// Output only. URI of the Service deployed.
   final String? uri;
@@ -975,7 +975,7 @@ class ServiceConfig extends Message {
   /// This configuration is only applicable to 1st Gen functions with Http
   /// trigger. By default https is optional for 1st Gen functions; 2nd Gen
   /// functions are https ONLY.
-  final ServiceConfig$SecurityLevel? securityLevel;
+  final ServiceConfig_SecurityLevel? securityLevel;
 
   /// Optional. The binary authorization policy to be checked when deploying the
   /// Cloud Run service.
@@ -1014,9 +1014,9 @@ class ServiceConfig extends Message {
       minInstanceCount: json['minInstanceCount'],
       vpcConnector: json['vpcConnector'],
       vpcConnectorEgressSettings: decode(json['vpcConnectorEgressSettings'],
-          ServiceConfig$VpcConnectorEgressSettings.fromJson),
+          ServiceConfig_VpcConnectorEgressSettings.fromJson),
       ingressSettings: decode(
-          json['ingressSettings'], ServiceConfig$IngressSettings.fromJson),
+          json['ingressSettings'], ServiceConfig_IngressSettings.fromJson),
       uri: json['uri'],
       serviceAccountEmail: json['serviceAccountEmail'],
       allTrafficOnLatestRevision: json['allTrafficOnLatestRevision'],
@@ -1026,7 +1026,7 @@ class ServiceConfig extends Message {
       revision: json['revision'],
       maxInstanceRequestConcurrency: json['maxInstanceRequestConcurrency'],
       securityLevel:
-          decode(json['securityLevel'], ServiceConfig$SecurityLevel.fromJson),
+          decode(json['securityLevel'], ServiceConfig_SecurityLevel.fromJson),
       binaryAuthorizationPolicy: json['binaryAuthorizationPolicy'],
     );
   }
@@ -1096,29 +1096,29 @@ class ServiceConfig extends Message {
 ///
 /// This controls what traffic is diverted through the VPC Access Connector
 /// resource. By default PRIVATE_RANGES_ONLY will be used.
-class ServiceConfig$VpcConnectorEgressSettings extends Enum {
+class ServiceConfig_VpcConnectorEgressSettings extends Enum {
   /// Unspecified.
   static const vpcConnectorEgressSettingsUnspecified =
-      ServiceConfig$VpcConnectorEgressSettings(
+      ServiceConfig_VpcConnectorEgressSettings(
           'VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED');
 
   /// Use the VPC Access Connector only for private IP space from RFC1918.
   static const privateRangesOnly =
-      ServiceConfig$VpcConnectorEgressSettings('PRIVATE_RANGES_ONLY');
+      ServiceConfig_VpcConnectorEgressSettings('PRIVATE_RANGES_ONLY');
 
   /// Force the use of VPC Access Connector for all egress traffic from the
   /// function.
   static const allTraffic =
-      ServiceConfig$VpcConnectorEgressSettings('ALL_TRAFFIC');
+      ServiceConfig_VpcConnectorEgressSettings('ALL_TRAFFIC');
 
-  const ServiceConfig$VpcConnectorEgressSettings(super.value);
+  const ServiceConfig_VpcConnectorEgressSettings(super.value);
 
-  factory ServiceConfig$VpcConnectorEgressSettings.fromJson(String json) =>
-      ServiceConfig$VpcConnectorEgressSettings(json);
+  factory ServiceConfig_VpcConnectorEgressSettings.fromJson(String json) =>
+      ServiceConfig_VpcConnectorEgressSettings(json);
 
   @override
   bool operator ==(Object other) =>
-      other is ServiceConfig$VpcConnectorEgressSettings && value == other.value;
+      other is ServiceConfig_VpcConnectorEgressSettings && value == other.value;
 
   @override
   String toString() => 'VpcConnectorEgressSettings.$value';
@@ -1129,30 +1129,30 @@ class ServiceConfig$VpcConnectorEgressSettings extends Enum {
 /// This controls what traffic can reach the function.
 ///
 /// If unspecified, ALLOW_ALL will be used.
-class ServiceConfig$IngressSettings extends Enum {
+class ServiceConfig_IngressSettings extends Enum {
   /// Unspecified.
   static const ingressSettingsUnspecified =
-      ServiceConfig$IngressSettings('INGRESS_SETTINGS_UNSPECIFIED');
+      ServiceConfig_IngressSettings('INGRESS_SETTINGS_UNSPECIFIED');
 
   /// Allow HTTP traffic from public and private sources.
-  static const allowAll = ServiceConfig$IngressSettings('ALLOW_ALL');
+  static const allowAll = ServiceConfig_IngressSettings('ALLOW_ALL');
 
   /// Allow HTTP traffic from only private VPC sources.
   static const allowInternalOnly =
-      ServiceConfig$IngressSettings('ALLOW_INTERNAL_ONLY');
+      ServiceConfig_IngressSettings('ALLOW_INTERNAL_ONLY');
 
   /// Allow HTTP traffic from private VPC sources and through GCLB.
   static const allowInternalAndGclb =
-      ServiceConfig$IngressSettings('ALLOW_INTERNAL_AND_GCLB');
+      ServiceConfig_IngressSettings('ALLOW_INTERNAL_AND_GCLB');
 
-  const ServiceConfig$IngressSettings(super.value);
+  const ServiceConfig_IngressSettings(super.value);
 
-  factory ServiceConfig$IngressSettings.fromJson(String json) =>
-      ServiceConfig$IngressSettings(json);
+  factory ServiceConfig_IngressSettings.fromJson(String json) =>
+      ServiceConfig_IngressSettings(json);
 
   @override
   bool operator ==(Object other) =>
-      other is ServiceConfig$IngressSettings && value == other.value;
+      other is ServiceConfig_IngressSettings && value == other.value;
 
   @override
   String toString() => 'IngressSettings.$value';
@@ -1164,29 +1164,29 @@ class ServiceConfig$IngressSettings extends Enum {
 ///
 /// Security level is only configurable for 1st Gen functions, If unspecified,
 /// SECURE_OPTIONAL will be used. 2nd Gen functions are SECURE_ALWAYS ONLY.
-class ServiceConfig$SecurityLevel extends Enum {
+class ServiceConfig_SecurityLevel extends Enum {
   /// Unspecified.
   static const securityLevelUnspecified =
-      ServiceConfig$SecurityLevel('SECURITY_LEVEL_UNSPECIFIED');
+      ServiceConfig_SecurityLevel('SECURITY_LEVEL_UNSPECIFIED');
 
   /// Requests for a URL that match this handler that do not use HTTPS are
   /// automatically redirected to the HTTPS URL with the same path. Query
   /// parameters are reserved for the redirect.
-  static const secureAlways = ServiceConfig$SecurityLevel('SECURE_ALWAYS');
+  static const secureAlways = ServiceConfig_SecurityLevel('SECURE_ALWAYS');
 
   /// Both HTTP and HTTPS requests with URLs that match the handler succeed
   /// without redirects. The application can examine the request to determine
   /// which protocol was used and respond accordingly.
-  static const secureOptional = ServiceConfig$SecurityLevel('SECURE_OPTIONAL');
+  static const secureOptional = ServiceConfig_SecurityLevel('SECURE_OPTIONAL');
 
-  const ServiceConfig$SecurityLevel(super.value);
+  const ServiceConfig_SecurityLevel(super.value);
 
-  factory ServiceConfig$SecurityLevel.fromJson(String json) =>
-      ServiceConfig$SecurityLevel(json);
+  factory ServiceConfig_SecurityLevel.fromJson(String json) =>
+      ServiceConfig_SecurityLevel(json);
 
   @override
   bool operator ==(Object other) =>
-      other is ServiceConfig$SecurityLevel && value == other.value;
+      other is ServiceConfig_SecurityLevel && value == other.value;
 
   @override
   String toString() => 'SecurityLevel.$value';
@@ -1279,7 +1279,7 @@ class SecretVolume extends Message {
   /// List of secret versions to mount for this secret. If empty, the `latest`
   /// version of the secret will be made available in a file named after the
   /// secret under the mount point.
-  final List<SecretVolume$SecretVersion>? versions;
+  final List<SecretVolume_SecretVersion>? versions;
 
   SecretVolume({
     this.mountPath,
@@ -1294,7 +1294,7 @@ class SecretVolume extends Message {
       projectId: json['projectId'],
       secret: json['secret'],
       versions:
-          decodeList(json['versions'], SecretVolume$SecretVersion.fromJson),
+          decodeList(json['versions'], SecretVolume_SecretVersion.fromJson),
     );
   }
 
@@ -1320,7 +1320,7 @@ class SecretVolume extends Message {
 }
 
 /// Configuration for a single version.
-class SecretVolume$SecretVersion extends Message {
+class SecretVolume_SecretVersion extends Message {
   static const String fullyQualifiedName =
       'google.cloud.functions.v2.SecretVolume.SecretVersion';
 
@@ -1335,13 +1335,13 @@ class SecretVolume$SecretVersion extends Message {
   /// secret value file at `/etc/secrets/secret_foo`.
   final String? path;
 
-  SecretVolume$SecretVersion({
+  SecretVolume_SecretVersion({
     this.version,
     this.path,
   }) : super(fullyQualifiedName);
 
-  factory SecretVolume$SecretVersion.fromJson(Map<String, dynamic> json) {
-    return SecretVolume$SecretVersion(
+  factory SecretVolume_SecretVersion.fromJson(Map<String, dynamic> json) {
+    return SecretVolume_SecretVersion(
       version: json['version'],
       path: json['path'],
     );
@@ -1407,7 +1407,7 @@ class EventTrigger extends Message {
 
   /// Optional. If unset, then defaults to ignoring failures (i.e. not retrying
   /// them).
-  final EventTrigger$RetryPolicy? retryPolicy;
+  final EventTrigger_RetryPolicy? retryPolicy;
 
   /// Optional. The name of the channel associated with the trigger in
   /// `projects/{project}/locations/{location}/channels/{channel}` format.
@@ -1445,7 +1445,7 @@ class EventTrigger extends Message {
       pubsubTopic: json['pubsubTopic'],
       serviceAccountEmail: json['serviceAccountEmail'],
       retryPolicy:
-          decode(json['retryPolicy'], EventTrigger$RetryPolicy.fromJson),
+          decode(json['retryPolicy'], EventTrigger_RetryPolicy.fromJson),
       channel: json['channel'],
       service: json['service'],
     );
@@ -1486,28 +1486,28 @@ class EventTrigger extends Message {
 
 /// Describes the retry policy in case of function's execution failure.
 /// Retried execution is charged as any other execution.
-class EventTrigger$RetryPolicy extends Enum {
+class EventTrigger_RetryPolicy extends Enum {
   /// Not specified.
   static const retryPolicyUnspecified =
-      EventTrigger$RetryPolicy('RETRY_POLICY_UNSPECIFIED');
+      EventTrigger_RetryPolicy('RETRY_POLICY_UNSPECIFIED');
 
   /// Do not retry.
   static const retryPolicyDoNotRetry =
-      EventTrigger$RetryPolicy('RETRY_POLICY_DO_NOT_RETRY');
+      EventTrigger_RetryPolicy('RETRY_POLICY_DO_NOT_RETRY');
 
   /// Retry on any failure, retry up to 7 days with an exponential backoff
   /// (capped at 10 seconds).
   static const retryPolicyRetry =
-      EventTrigger$RetryPolicy('RETRY_POLICY_RETRY');
+      EventTrigger_RetryPolicy('RETRY_POLICY_RETRY');
 
-  const EventTrigger$RetryPolicy(super.value);
+  const EventTrigger_RetryPolicy(super.value);
 
-  factory EventTrigger$RetryPolicy.fromJson(String json) =>
-      EventTrigger$RetryPolicy(json);
+  factory EventTrigger_RetryPolicy.fromJson(String json) =>
+      EventTrigger_RetryPolicy(json);
 
   @override
   bool operator ==(Object other) =>
-      other is EventTrigger$RetryPolicy && value == other.value;
+      other is EventTrigger_RetryPolicy && value == other.value;
 
   @override
   String toString() => 'RetryPolicy.$value';
@@ -2090,7 +2090,7 @@ class ListRuntimesResponse extends Message {
       'google.cloud.functions.v2.ListRuntimesResponse';
 
   /// The runtimes that match the request.
-  final List<ListRuntimesResponse$Runtime>? runtimes;
+  final List<ListRuntimesResponse_Runtime>? runtimes;
 
   ListRuntimesResponse({
     this.runtimes,
@@ -2099,7 +2099,7 @@ class ListRuntimesResponse extends Message {
   factory ListRuntimesResponse.fromJson(Map<String, dynamic> json) {
     return ListRuntimesResponse(
       runtimes:
-          decodeList(json['runtimes'], ListRuntimesResponse$Runtime.fromJson),
+          decodeList(json['runtimes'], ListRuntimesResponse_Runtime.fromJson),
     );
   }
 
@@ -2116,7 +2116,7 @@ class ListRuntimesResponse extends Message {
 
 /// Describes a runtime and any special information (e.g., deprecation status)
 /// related to it.
-class ListRuntimesResponse$Runtime extends Message {
+class ListRuntimesResponse_Runtime extends Message {
   static const String fullyQualifiedName =
       'google.cloud.functions.v2.ListRuntimesResponse.Runtime';
 
@@ -2127,7 +2127,7 @@ class ListRuntimesResponse$Runtime extends Message {
   final String? displayName;
 
   /// The stage of life this runtime is in, e.g., BETA, GA, etc.
-  final ListRuntimesResponse$RuntimeStage? stage;
+  final ListRuntimesResponse_RuntimeStage? stage;
 
   /// Warning messages, e.g., a deprecation warning.
   final List<String>? warnings;
@@ -2141,7 +2141,7 @@ class ListRuntimesResponse$Runtime extends Message {
   /// Decommission date for the runtime.
   final Date? decommissionDate;
 
-  ListRuntimesResponse$Runtime({
+  ListRuntimesResponse_Runtime({
     this.name,
     this.displayName,
     this.stage,
@@ -2151,11 +2151,11 @@ class ListRuntimesResponse$Runtime extends Message {
     this.decommissionDate,
   }) : super(fullyQualifiedName);
 
-  factory ListRuntimesResponse$Runtime.fromJson(Map<String, dynamic> json) {
-    return ListRuntimesResponse$Runtime(
+  factory ListRuntimesResponse_Runtime.fromJson(Map<String, dynamic> json) {
+    return ListRuntimesResponse_Runtime(
       name: json['name'],
       displayName: json['displayName'],
-      stage: decode(json['stage'], ListRuntimesResponse$RuntimeStage.fromJson),
+      stage: decode(json['stage'], ListRuntimesResponse_RuntimeStage.fromJson),
       warnings: (json['warnings'] as List?)?.cast(),
       environment: decode(json['environment'], Environment.fromJson),
       deprecationDate: decode(json['deprecationDate'], Date.fromJson),
@@ -2190,38 +2190,38 @@ class ListRuntimesResponse$Runtime extends Message {
 }
 
 /// The various stages that a runtime can be in.
-class ListRuntimesResponse$RuntimeStage extends Enum {
+class ListRuntimesResponse_RuntimeStage extends Enum {
   /// Not specified.
   static const runtimeStageUnspecified =
-      ListRuntimesResponse$RuntimeStage('RUNTIME_STAGE_UNSPECIFIED');
+      ListRuntimesResponse_RuntimeStage('RUNTIME_STAGE_UNSPECIFIED');
 
   /// The runtime is in development.
-  static const development = ListRuntimesResponse$RuntimeStage('DEVELOPMENT');
+  static const development = ListRuntimesResponse_RuntimeStage('DEVELOPMENT');
 
   /// The runtime is in the Alpha stage.
-  static const alpha = ListRuntimesResponse$RuntimeStage('ALPHA');
+  static const alpha = ListRuntimesResponse_RuntimeStage('ALPHA');
 
   /// The runtime is in the Beta stage.
-  static const beta = ListRuntimesResponse$RuntimeStage('BETA');
+  static const beta = ListRuntimesResponse_RuntimeStage('BETA');
 
   /// The runtime is generally available.
-  static const ga = ListRuntimesResponse$RuntimeStage('GA');
+  static const ga = ListRuntimesResponse_RuntimeStage('GA');
 
   /// The runtime is deprecated.
-  static const deprecated = ListRuntimesResponse$RuntimeStage('DEPRECATED');
+  static const deprecated = ListRuntimesResponse_RuntimeStage('DEPRECATED');
 
   /// The runtime is no longer supported.
   static const decommissioned =
-      ListRuntimesResponse$RuntimeStage('DECOMMISSIONED');
+      ListRuntimesResponse_RuntimeStage('DECOMMISSIONED');
 
-  const ListRuntimesResponse$RuntimeStage(super.value);
+  const ListRuntimesResponse_RuntimeStage(super.value);
 
-  factory ListRuntimesResponse$RuntimeStage.fromJson(String json) =>
-      ListRuntimesResponse$RuntimeStage(json);
+  factory ListRuntimesResponse_RuntimeStage.fromJson(String json) =>
+      ListRuntimesResponse_RuntimeStage(json);
 
   @override
   bool operator ==(Object other) =>
-      other is ListRuntimesResponse$RuntimeStage && value == other.value;
+      other is ListRuntimesResponse_RuntimeStage && value == other.value;
 
   @override
   String toString() => 'RuntimeStage.$value';
@@ -2430,13 +2430,13 @@ class Stage extends Message {
   static const String fullyQualifiedName = 'google.cloud.functions.v2.Stage';
 
   /// Name of the Stage. This will be unique for each Stage.
-  final Stage$Name? name;
+  final Stage_Name? name;
 
   /// Message describing the Stage
   final String? message;
 
   /// Current state of the Stage
-  final Stage$State? state;
+  final Stage_State? state;
 
   /// Resource of the Stage
   final String? resource;
@@ -2458,9 +2458,9 @@ class Stage extends Message {
 
   factory Stage.fromJson(Map<String, dynamic> json) {
     return Stage(
-      name: decode(json['name'], Stage$Name.fromJson),
+      name: decode(json['name'], Stage_Name.fromJson),
       message: json['message'],
-      state: decode(json['state'], Stage$State.fromJson),
+      state: decode(json['state'], Stage_State.fromJson),
       resource: json['resource'],
       resourceUri: json['resourceUri'],
       stateMessages: decodeList(json['stateMessages'], StateMessage.fromJson),
@@ -2493,60 +2493,60 @@ class Stage extends Message {
 }
 
 /// Possible names for a Stage
-class Stage$Name extends Enum {
+class Stage_Name extends Enum {
   /// Not specified. Invalid name.
-  static const nameUnspecified = Stage$Name('NAME_UNSPECIFIED');
+  static const nameUnspecified = Stage_Name('NAME_UNSPECIFIED');
 
   /// Artifact Registry Stage
-  static const artifactRegistry = Stage$Name('ARTIFACT_REGISTRY');
+  static const artifactRegistry = Stage_Name('ARTIFACT_REGISTRY');
 
   /// Build Stage
-  static const build = Stage$Name('BUILD');
+  static const build = Stage_Name('BUILD');
 
   /// Service Stage
-  static const service = Stage$Name('SERVICE');
+  static const service = Stage_Name('SERVICE');
 
   /// Trigger Stage
-  static const trigger = Stage$Name('TRIGGER');
+  static const trigger = Stage_Name('TRIGGER');
 
   /// Service Rollback Stage
-  static const serviceRollback = Stage$Name('SERVICE_ROLLBACK');
+  static const serviceRollback = Stage_Name('SERVICE_ROLLBACK');
 
   /// Trigger Rollback Stage
-  static const triggerRollback = Stage$Name('TRIGGER_ROLLBACK');
+  static const triggerRollback = Stage_Name('TRIGGER_ROLLBACK');
 
-  const Stage$Name(super.value);
+  const Stage_Name(super.value);
 
-  factory Stage$Name.fromJson(String json) => Stage$Name(json);
+  factory Stage_Name.fromJson(String json) => Stage_Name(json);
 
   @override
-  bool operator ==(Object other) => other is Stage$Name && value == other.value;
+  bool operator ==(Object other) => other is Stage_Name && value == other.value;
 
   @override
   String toString() => 'Name.$value';
 }
 
 /// Possible states for a Stage
-class Stage$State extends Enum {
+class Stage_State extends Enum {
   /// Not specified. Invalid state.
-  static const stateUnspecified = Stage$State('STATE_UNSPECIFIED');
+  static const stateUnspecified = Stage_State('STATE_UNSPECIFIED');
 
   /// Stage has not started.
-  static const notStarted = Stage$State('NOT_STARTED');
+  static const notStarted = Stage_State('NOT_STARTED');
 
   /// Stage is in progress.
-  static const inProgress = Stage$State('IN_PROGRESS');
+  static const inProgress = Stage_State('IN_PROGRESS');
 
   /// Stage has completed.
-  static const complete = Stage$State('COMPLETE');
+  static const complete = Stage_State('COMPLETE');
 
-  const Stage$State(super.value);
+  const Stage_State(super.value);
 
-  factory Stage$State.fromJson(String json) => Stage$State(json);
+  factory Stage_State.fromJson(String json) => Stage_State(json);
 
   @override
   bool operator ==(Object other) =>
-      other is Stage$State && value == other.value;
+      other is Stage_State && value == other.value;
 
   @override
   String toString() => 'State.$value';
diff --git a/generator/dart/generated/google_cloud_iam_v1/lib/iam.dart b/generator/dart/generated/google_cloud_iam_v1/lib/iam.dart
index 4022567957..5c3ad002b8 100755
--- a/generator/dart/generated/google_cloud_iam_v1/lib/iam.dart
+++ b/generator/dart/generated/google_cloud_iam_v1/lib/iam.dart
@@ -703,7 +703,7 @@ class AuditLogConfig extends Message {
   static const String fullyQualifiedName = 'google.iam.v1.AuditLogConfig';
 
   /// The log type that this config enables.
-  final AuditLogConfig$LogType? logType;
+  final AuditLogConfig_LogType? logType;
 
   /// Specifies the identities that do not cause logging for this type of
   /// permission.
@@ -718,7 +718,7 @@ class AuditLogConfig extends Message {
 
   factory AuditLogConfig.fromJson(Map<String, dynamic> json) {
     return AuditLogConfig(
-      logType: decode(json['logType'], AuditLogConfig$LogType.fromJson),
+      logType: decode(json['logType'], AuditLogConfig_LogType.fromJson),
       exemptedMembers: (json['exemptedMembers'] as List?)?.cast(),
     );
   }
@@ -742,28 +742,28 @@ class AuditLogConfig extends Message {
 
 /// The list of valid permission types for which logging can be configured.
 /// Admin writes are always logged, and are not configurable.
-class AuditLogConfig$LogType extends Enum {
+class AuditLogConfig_LogType extends Enum {
   /// Default case. Should never be this.
   static const logTypeUnspecified =
-      AuditLogConfig$LogType('LOG_TYPE_UNSPECIFIED');
+      AuditLogConfig_LogType('LOG_TYPE_UNSPECIFIED');
 
   /// Admin reads. Example: CloudIAM getIamPolicy
-  static const adminRead = AuditLogConfig$LogType('ADMIN_READ');
+  static const adminRead = AuditLogConfig_LogType('ADMIN_READ');
 
   /// Data writes. Example: CloudSQL Users create
-  static const dataWrite = AuditLogConfig$LogType('DATA_WRITE');
+  static const dataWrite = AuditLogConfig_LogType('DATA_WRITE');
 
   /// Data reads. Example: CloudSQL Users list
-  static const dataRead = AuditLogConfig$LogType('DATA_READ');
+  static const dataRead = AuditLogConfig_LogType('DATA_READ');
 
-  const AuditLogConfig$LogType(super.value);
+  const AuditLogConfig_LogType(super.value);
 
-  factory AuditLogConfig$LogType.fromJson(String json) =>
-      AuditLogConfig$LogType(json);
+  factory AuditLogConfig_LogType.fromJson(String json) =>
+      AuditLogConfig_LogType(json);
 
   @override
   bool operator ==(Object other) =>
-      other is AuditLogConfig$LogType && value == other.value;
+      other is AuditLogConfig_LogType && value == other.value;
 
   @override
   String toString() => 'LogType.$value';
@@ -812,7 +812,7 @@ class BindingDelta extends Message {
 
   /// The action that was performed on a Binding.
   /// Required
-  final BindingDelta$Action? action;
+  final BindingDelta_Action? action;
 
   /// Role that is assigned to `members`.
   /// For example, `roles/viewer`, `roles/editor`, or `roles/owner`.
@@ -836,7 +836,7 @@ class BindingDelta extends Message {
 
   factory BindingDelta.fromJson(Map<String, dynamic> json) {
     return BindingDelta(
-      action: decode(json['action'], BindingDelta$Action.fromJson),
+      action: decode(json['action'], BindingDelta_Action.fromJson),
       role: json['role'],
       member: json['member'],
       condition: decode(json['condition'], Expr.fromJson),
@@ -865,24 +865,24 @@ class BindingDelta extends Message {
 }
 
 /// The type of action performed on a Binding in a policy.
-class BindingDelta$Action extends Enum {
+class BindingDelta_Action extends Enum {
   /// Unspecified.
-  static const actionUnspecified = BindingDelta$Action('ACTION_UNSPECIFIED');
+  static const actionUnspecified = BindingDelta_Action('ACTION_UNSPECIFIED');
 
   /// Addition of a Binding.
-  static const add = BindingDelta$Action('ADD');
+  static const add = BindingDelta_Action('ADD');
 
   /// Removal of a Binding.
-  static const remove = BindingDelta$Action('REMOVE');
+  static const remove = BindingDelta_Action('REMOVE');
 
-  const BindingDelta$Action(super.value);
+  const BindingDelta_Action(super.value);
 
-  factory BindingDelta$Action.fromJson(String json) =>
-      BindingDelta$Action(json);
+  factory BindingDelta_Action.fromJson(String json) =>
+      BindingDelta_Action(json);
 
   @override
   bool operator ==(Object other) =>
-      other is BindingDelta$Action && value == other.value;
+      other is BindingDelta_Action && value == other.value;
 
   @override
   String toString() => 'Action.$value';
@@ -895,7 +895,7 @@ class AuditConfigDelta extends Message {
 
   /// The action that was performed on an audit configuration in a policy.
   /// Required
-  final AuditConfigDelta$Action? action;
+  final AuditConfigDelta_Action? action;
 
   /// Specifies a service that was configured for Cloud Audit Logging.
   /// For example, `storage.googleapis.com`, `cloudsql.googleapis.com`.
@@ -922,7 +922,7 @@ class AuditConfigDelta extends Message {
 
   factory AuditConfigDelta.fromJson(Map<String, dynamic> json) {
     return AuditConfigDelta(
-      action: decode(json['action'], AuditConfigDelta$Action.fromJson),
+      action: decode(json['action'], AuditConfigDelta_Action.fromJson),
       service: json['service'],
       exemptedMember: json['exemptedMember'],
       logType: json['logType'],
@@ -952,25 +952,25 @@ class AuditConfigDelta extends Message {
 }
 
 /// The type of action performed on an audit configuration in a policy.
-class AuditConfigDelta$Action extends Enum {
+class AuditConfigDelta_Action extends Enum {
   /// Unspecified.
   static const actionUnspecified =
-      AuditConfigDelta$Action('ACTION_UNSPECIFIED');
+      AuditConfigDelta_Action('ACTION_UNSPECIFIED');
 
   /// Addition of an audit configuration.
-  static const add = AuditConfigDelta$Action('ADD');
+  static const add = AuditConfigDelta_Action('ADD');
 
   /// Removal of an audit configuration.
-  static const remove = AuditConfigDelta$Action('REMOVE');
+  static const remove = AuditConfigDelta_Action('REMOVE');
 
-  const AuditConfigDelta$Action(super.value);
+  const AuditConfigDelta_Action(super.value);
 
-  factory AuditConfigDelta$Action.fromJson(String json) =>
-      AuditConfigDelta$Action(json);
+  factory AuditConfigDelta_Action.fromJson(String json) =>
+      AuditConfigDelta_Action(json);
 
   @override
   bool operator ==(Object other) =>
-      other is AuditConfigDelta$Action && value == other.value;
+      other is AuditConfigDelta_Action && value == other.value;
 
   @override
   String toString() => 'Action.$value';
diff --git a/generator/dart/generated/google_cloud_language_v2/lib/language.dart b/generator/dart/generated/google_cloud_language_v2/lib/language.dart
index 16e90ee875..e5223dcaa2 100755
--- a/generator/dart/generated/google_cloud_language_v2/lib/language.dart
+++ b/generator/dart/generated/google_cloud_language_v2/lib/language.dart
@@ -88,7 +88,7 @@ class Document extends Message {
 
   /// Required. If the type is not set or is `TYPE_UNSPECIFIED`,
   /// returns an `INVALID_ARGUMENT` error.
-  final Document$Type? type;
+  final Document_Type? type;
 
   /// The content of the input in string format.
   /// Cloud audit logging exempt since it is based on user data.
@@ -119,7 +119,7 @@ class Document extends Message {
 
   factory Document.fromJson(Map<String, dynamic> json) {
     return Document(
-      type: decode(json['type'], Document$Type.fromJson),
+      type: decode(json['type'], Document_Type.fromJson),
       content: json['content'],
       gcsContentUri: json['gcsContentUri'],
       languageCode: json['languageCode'],
@@ -149,23 +149,23 @@ class Document extends Message {
 }
 
 /// The document types enum.
-class Document$Type extends Enum {
+class Document_Type extends Enum {
   /// The content type is not specified.
-  static const typeUnspecified = Document$Type('TYPE_UNSPECIFIED');
+  static const typeUnspecified = Document_Type('TYPE_UNSPECIFIED');
 
   /// Plain text
-  static const plainText = Document$Type('PLAIN_TEXT');
+  static const plainText = Document_Type('PLAIN_TEXT');
 
   /// HTML
-  static const html = Document$Type('HTML');
+  static const html = Document_Type('HTML');
 
-  const Document$Type(super.value);
+  const Document_Type(super.value);
 
-  factory Document$Type.fromJson(String json) => Document$Type(json);
+  factory Document_Type.fromJson(String json) => Document_Type(json);
 
   @override
   bool operator ==(Object other) =>
-      other is Document$Type && value == other.value;
+      other is Document_Type && value == other.value;
 
   @override
   String toString() => 'Type.$value';
@@ -217,7 +217,7 @@ class Entity extends Message {
   final String? name;
 
   /// The entity type.
-  final Entity$Type? type;
+  final Entity_Type? type;
 
   /// Metadata associated with the entity.
   ///
@@ -246,7 +246,7 @@ class Entity extends Message {
   factory Entity.fromJson(Map<String, dynamic> json) {
     return Entity(
       name: json['name'],
-      type: decode(json['type'], Entity$Type.fromJson),
+      type: decode(json['type'], Entity_Type.fromJson),
       metadata: (json['metadata'] as Map?)?.cast(),
       mentions: decodeList(json['mentions'], EntityMention.fromJson),
       sentiment: decode(json['sentiment'], Sentiment.fromJson),
@@ -277,30 +277,30 @@ class Entity extends Message {
 /// The type of the entity. The table
 /// below lists the associated fields for entities that have different
 /// metadata.
-class Entity$Type extends Enum {
+class Entity_Type extends Enum {
   /// Unknown
-  static const unknown = Entity$Type('UNKNOWN');
+  static const unknown = Entity_Type('UNKNOWN');
 
   /// Person
-  static const person = Entity$Type('PERSON');
+  static const person = Entity_Type('PERSON');
 
   /// Location
-  static const location = Entity$Type('LOCATION');
+  static const location = Entity_Type('LOCATION');
 
   /// Organization
-  static const organization = Entity$Type('ORGANIZATION');
+  static const organization = Entity_Type('ORGANIZATION');
 
   /// Event
-  static const event = Entity$Type('EVENT');
+  static const event = Entity_Type('EVENT');
 
   /// Artwork
-  static const workOfArt = Entity$Type('WORK_OF_ART');
+  static const workOfArt = Entity_Type('WORK_OF_ART');
 
   /// Consumer product
-  static const consumerGood = Entity$Type('CONSUMER_GOOD');
+  static const consumerGood = Entity_Type('CONSUMER_GOOD');
 
   /// Other types of entities
-  static const other = Entity$Type('OTHER');
+  static const other = Entity_Type('OTHER');
 
   /// Phone number
   ///
@@ -313,7 +313,7 @@ class Entity$Type extends Enum {
   /// * `area_code` - region or area code, if detected
   /// * `extension` - phone extension (to be dialed after connection), if
   /// detected
-  static const phoneNumber = Entity$Type('PHONE_NUMBER');
+  static const phoneNumber = Entity_Type('PHONE_NUMBER');
 
   /// Address
   ///
@@ -330,7 +330,7 @@ class Entity$Type extends Enum {
   /// detected
   /// * `sublocality` - used in Asian addresses to demark a district within a
   /// city, if detected
-  static const address = Entity$Type('ADDRESS');
+  static const address = Entity_Type('ADDRESS');
 
   /// Date
   ///
@@ -339,25 +339,25 @@ class Entity$Type extends Enum {
   /// * `year` - four digit year, if detected
   /// * `month` - two digit month number, if detected
   /// * `day` - two digit day number, if detected
-  static const date = Entity$Type('DATE');
+  static const date = Entity_Type('DATE');
 
   /// Number
   ///
   /// The metadata is the number itself.
-  static const number = Entity$Type('NUMBER');
+  static const number = Entity_Type('NUMBER');
 
   /// Price
   ///
   /// The metadata identifies the `value` and `currency`.
-  static const price = Entity$Type('PRICE');
+  static const price = Entity_Type('PRICE');
 
-  const Entity$Type(super.value);
+  const Entity_Type(super.value);
 
-  factory Entity$Type.fromJson(String json) => Entity$Type(json);
+  factory Entity_Type.fromJson(String json) => Entity_Type(json);
 
   @override
   bool operator ==(Object other) =>
-      other is Entity$Type && value == other.value;
+      other is Entity_Type && value == other.value;
 
   @override
   String toString() => 'Type.$value';
@@ -417,7 +417,7 @@ class EntityMention extends Message {
   final TextSpan? text;
 
   /// The type of the entity mention.
-  final EntityMention$Type? type;
+  final EntityMention_Type? type;
 
   /// For calls to `AnalyzeEntitySentiment` or if
   /// `AnnotateTextRequest.Features.extract_entity_sentiment`
@@ -441,7 +441,7 @@ class EntityMention extends Message {
   factory EntityMention.fromJson(Map<String, dynamic> json) {
     return EntityMention(
       text: decode(json['text'], TextSpan.fromJson),
-      type: decode(json['type'], EntityMention$Type.fromJson),
+      type: decode(json['type'], EntityMention_Type.fromJson),
       sentiment: decode(json['sentiment'], Sentiment.fromJson),
       probability: (json['probability'] as num?)?.toDouble(),
     );
@@ -468,23 +468,23 @@ class EntityMention extends Message {
 }
 
 /// The supported types of mentions.
-class EntityMention$Type extends Enum {
+class EntityMention_Type extends Enum {
   /// Unknown
-  static const typeUnknown = EntityMention$Type('TYPE_UNKNOWN');
+  static const typeUnknown = EntityMention_Type('TYPE_UNKNOWN');
 
   /// Proper name
-  static const proper = EntityMention$Type('PROPER');
+  static const proper = EntityMention_Type('PROPER');
 
   /// Common noun (or noun compound)
-  static const common = EntityMention$Type('COMMON');
+  static const common = EntityMention_Type('COMMON');
 
-  const EntityMention$Type(super.value);
+  const EntityMention_Type(super.value);
 
-  factory EntityMention$Type.fromJson(String json) => EntityMention$Type(json);
+  factory EntityMention_Type.fromJson(String json) => EntityMention_Type(json);
 
   @override
   bool operator ==(Object other) =>
-      other is EntityMention$Type && value == other.value;
+      other is EntityMention_Type && value == other.value;
 
   @override
   String toString() => 'Type.$value';
@@ -863,7 +863,7 @@ class ModerateTextRequest extends Message {
   final Document? document;
 
   /// Optional. The model version to use for ModerateText.
-  final ModerateTextRequest$ModelVersion? modelVersion;
+  final ModerateTextRequest_ModelVersion? modelVersion;
 
   ModerateTextRequest({
     this.document,
@@ -874,7 +874,7 @@ class ModerateTextRequest extends Message {
     return ModerateTextRequest(
       document: decode(json['document'], Document.fromJson),
       modelVersion: decode(
-          json['modelVersion'], ModerateTextRequest$ModelVersion.fromJson),
+          json['modelVersion'], ModerateTextRequest_ModelVersion.fromJson),
     );
   }
 
@@ -896,31 +896,31 @@ class ModerateTextRequest extends Message {
 }
 
 /// The model version to use for ModerateText.
-class ModerateTextRequest$ModelVersion extends Enum {
+class ModerateTextRequest_ModelVersion extends Enum {
   /// The default model version.
   static const modelVersionUnspecified =
-      ModerateTextRequest$ModelVersion('MODEL_VERSION_UNSPECIFIED');
+      ModerateTextRequest_ModelVersion('MODEL_VERSION_UNSPECIFIED');
 
   /// Use the v1 model, this model is used by default when not provided.
   /// The v1 model only returns probability (confidence) score for each
   /// category.
   static const modelVersion1 =
-      ModerateTextRequest$ModelVersion('MODEL_VERSION_1');
+      ModerateTextRequest_ModelVersion('MODEL_VERSION_1');
 
   /// Use the v2 model.
   /// The v2 model only returns probability (confidence) score for each
   /// category, and returns severity score for a subset of the categories.
   static const modelVersion2 =
-      ModerateTextRequest$ModelVersion('MODEL_VERSION_2');
+      ModerateTextRequest_ModelVersion('MODEL_VERSION_2');
 
-  const ModerateTextRequest$ModelVersion(super.value);
+  const ModerateTextRequest_ModelVersion(super.value);
 
-  factory ModerateTextRequest$ModelVersion.fromJson(String json) =>
-      ModerateTextRequest$ModelVersion(json);
+  factory ModerateTextRequest_ModelVersion.fromJson(String json) =>
+      ModerateTextRequest_ModelVersion(json);
 
   @override
   bool operator ==(Object other) =>
-      other is ModerateTextRequest$ModelVersion && value == other.value;
+      other is ModerateTextRequest_ModelVersion && value == other.value;
 
   @override
   String toString() => 'ModelVersion.$value';
@@ -989,7 +989,7 @@ class AnnotateTextRequest extends Message {
   final Document? document;
 
   /// Required. The enabled features.
-  final AnnotateTextRequest$Features? features;
+  final AnnotateTextRequest_Features? features;
 
   /// The encoding type used by the API to calculate offsets.
   final EncodingType? encodingType;
@@ -1003,7 +1003,7 @@ class AnnotateTextRequest extends Message {
   factory AnnotateTextRequest.fromJson(Map<String, dynamic> json) {
     return AnnotateTextRequest(
       document: decode(json['document'], Document.fromJson),
-      features: decode(json['features'], AnnotateTextRequest$Features.fromJson),
+      features: decode(json['features'], AnnotateTextRequest_Features.fromJson),
       encodingType: decode(json['encodingType'], EncodingType.fromJson),
     );
   }
@@ -1028,7 +1028,7 @@ class AnnotateTextRequest extends Message {
 
 /// All available features.
 /// Setting each one to true will enable that specific analysis for the input.
-class AnnotateTextRequest$Features extends Message {
+class AnnotateTextRequest_Features extends Message {
   static const String fullyQualifiedName =
       'google.cloud.language.v2.AnnotateTextRequest.Features';
 
@@ -1044,15 +1044,15 @@ class AnnotateTextRequest$Features extends Message {
   /// Optional. Moderate the document for harmful and sensitive categories.
   final bool? moderateText;
 
-  AnnotateTextRequest$Features({
+  AnnotateTextRequest_Features({
     this.extractEntities,
     this.extractDocumentSentiment,
     this.classifyText,
     this.moderateText,
   }) : super(fullyQualifiedName);
 
-  factory AnnotateTextRequest$Features.fromJson(Map<String, dynamic> json) {
-    return AnnotateTextRequest$Features(
+  factory AnnotateTextRequest_Features.fromJson(Map<String, dynamic> json) {
+    return AnnotateTextRequest_Features(
       extractEntities: json['extractEntities'],
       extractDocumentSentiment: json['extractDocumentSentiment'],
       classifyText: json['classifyText'],
diff --git a/generator/dart/generated/google_cloud_rpc/lib/rpc.dart b/generator/dart/generated/google_cloud_rpc/lib/rpc.dart
index 51562b3ae3..d987837987 100755
--- a/generator/dart/generated/google_cloud_rpc/lib/rpc.dart
+++ b/generator/dart/generated/google_cloud_rpc/lib/rpc.dart
@@ -209,7 +209,7 @@ class QuotaFailure extends Message {
   static const String fullyQualifiedName = 'google.rpc.QuotaFailure';
 
   /// Describes all quota violations.
-  final List<QuotaFailure$Violation>? violations;
+  final List<QuotaFailure_Violation>? violations;
 
   QuotaFailure({
     this.violations,
@@ -218,7 +218,7 @@ class QuotaFailure extends Message {
   factory QuotaFailure.fromJson(Map<String, dynamic> json) {
     return QuotaFailure(
       violations:
-          decodeList(json['violations'], QuotaFailure$Violation.fromJson),
+          decodeList(json['violations'], QuotaFailure_Violation.fromJson),
     );
   }
 
@@ -235,7 +235,7 @@ class QuotaFailure extends Message {
 
 /// A message type used to describe a single quota violation.  For example, a
 /// daily quota or a custom quota that was exceeded.
-class QuotaFailure$Violation extends Message {
+class QuotaFailure_Violation extends Message {
   static const String fullyQualifiedName = 'google.rpc.QuotaFailure.Violation';
 
   /// The subject on which the quota check failed.
@@ -252,13 +252,13 @@ class QuotaFailure$Violation extends Message {
   /// exceeded".
   final String? description;
 
-  QuotaFailure$Violation({
+  QuotaFailure_Violation({
     this.subject,
     this.description,
   }) : super(fullyQualifiedName);
 
-  factory QuotaFailure$Violation.fromJson(Map<String, dynamic> json) {
-    return QuotaFailure$Violation(
+  factory QuotaFailure_Violation.fromJson(Map<String, dynamic> json) {
+    return QuotaFailure_Violation(
       subject: json['subject'],
       description: json['description'],
     );
@@ -291,7 +291,7 @@ class PreconditionFailure extends Message {
   static const String fullyQualifiedName = 'google.rpc.PreconditionFailure';
 
   /// Describes all precondition violations.
-  final List<PreconditionFailure$Violation>? violations;
+  final List<PreconditionFailure_Violation>? violations;
 
   PreconditionFailure({
     this.violations,
@@ -300,7 +300,7 @@ class PreconditionFailure extends Message {
   factory PreconditionFailure.fromJson(Map<String, dynamic> json) {
     return PreconditionFailure(
       violations: decodeList(
-          json['violations'], PreconditionFailure$Violation.fromJson),
+          json['violations'], PreconditionFailure_Violation.fromJson),
     );
   }
 
@@ -316,7 +316,7 @@ class PreconditionFailure extends Message {
 }
 
 /// A message type used to describe a single precondition failure.
-class PreconditionFailure$Violation extends Message {
+class PreconditionFailure_Violation extends Message {
   static const String fullyQualifiedName =
       'google.rpc.PreconditionFailure.Violation';
 
@@ -336,14 +336,14 @@ class PreconditionFailure$Violation extends Message {
   /// For example: "Terms of service not accepted".
   final String? description;
 
-  PreconditionFailure$Violation({
+  PreconditionFailure_Violation({
     this.type,
     this.subject,
     this.description,
   }) : super(fullyQualifiedName);
 
-  factory PreconditionFailure$Violation.fromJson(Map<String, dynamic> json) {
-    return PreconditionFailure$Violation(
+  factory PreconditionFailure_Violation.fromJson(Map<String, dynamic> json) {
+    return PreconditionFailure_Violation(
       type: json['type'],
       subject: json['subject'],
       description: json['description'],
@@ -376,7 +376,7 @@ class BadRequest extends Message {
   static const String fullyQualifiedName = 'google.rpc.BadRequest';
 
   /// Describes all violations in a client request.
-  final List<BadRequest$FieldViolation>? fieldViolations;
+  final List<BadRequest_FieldViolation>? fieldViolations;
 
   BadRequest({
     this.fieldViolations,
@@ -385,7 +385,7 @@ class BadRequest extends Message {
   factory BadRequest.fromJson(Map<String, dynamic> json) {
     return BadRequest(
       fieldViolations: decodeList(
-          json['fieldViolations'], BadRequest$FieldViolation.fromJson),
+          json['fieldViolations'], BadRequest_FieldViolation.fromJson),
     );
   }
 
@@ -402,7 +402,7 @@ class BadRequest extends Message {
 }
 
 /// A message type used to describe a single bad request field.
-class BadRequest$FieldViolation extends Message {
+class BadRequest_FieldViolation extends Message {
   static const String fullyQualifiedName =
       'google.rpc.BadRequest.FieldViolation';
 
@@ -460,15 +460,15 @@ class BadRequest$FieldViolation extends Message {
   /// return to the API consumer.
   final LocalizedMessage? localizedMessage;
 
-  BadRequest$FieldViolation({
+  BadRequest_FieldViolation({
     this.field,
     this.description,
     this.reason,
     this.localizedMessage,
   }) : super(fullyQualifiedName);
 
-  factory BadRequest$FieldViolation.fromJson(Map<String, dynamic> json) {
-    return BadRequest$FieldViolation(
+  factory BadRequest_FieldViolation.fromJson(Map<String, dynamic> json) {
+    return BadRequest_FieldViolation(
       field: json['field'],
       description: json['description'],
       reason: json['reason'],
@@ -614,7 +614,7 @@ class Help extends Message {
   static const String fullyQualifiedName = 'google.rpc.Help';
 
   /// URL(s) pointing to additional information on handling the current error.
-  final List<Help$Link>? links;
+  final List<Help_Link>? links;
 
   Help({
     this.links,
@@ -622,7 +622,7 @@ class Help extends Message {
 
   factory Help.fromJson(Map<String, dynamic> json) {
     return Help(
-      links: decodeList(json['links'], Help$Link.fromJson),
+      links: decodeList(json['links'], Help_Link.fromJson),
     );
   }
 
@@ -638,7 +638,7 @@ class Help extends Message {
 }
 
 /// Describes a URL link.
-class Help$Link extends Message {
+class Help_Link extends Message {
   static const String fullyQualifiedName = 'google.rpc.Help.Link';
 
   /// Describes what the link offers.
@@ -647,13 +647,13 @@ class Help$Link extends Message {
   /// The URL of the link.
   final String? url;
 
-  Help$Link({
+  Help_Link({
     this.description,
     this.url,
   }) : super(fullyQualifiedName);
 
-  factory Help$Link.fromJson(Map<String, dynamic> json) {
-    return Help$Link(
+  factory Help_Link.fromJson(Map<String, dynamic> json) {
+    return Help_Link(
       description: json['description'],
       url: json['url'],
     );
diff --git a/generator/dart/generated/google_cloud_secretmanager_v1/lib/secretmanager.dart b/generator/dart/generated/google_cloud_secretmanager_v1/lib/secretmanager.dart
index bfe4111a49..acbcd0dbdf 100755
--- a/generator/dart/generated/google_cloud_secretmanager_v1/lib/secretmanager.dart
+++ b/generator/dart/generated/google_cloud_secretmanager_v1/lib/secretmanager.dart
@@ -417,7 +417,7 @@ class SecretVersion extends Message {
 
   /// Output only. The current state of the
   /// `SecretVersion`.
-  final SecretVersion$State? state;
+  final SecretVersion_State? state;
 
   /// The replication status of the
   /// `SecretVersion`.
@@ -465,7 +465,7 @@ class SecretVersion extends Message {
       name: json['name'],
       createTime: decode(json['createTime'], Timestamp.fromJson),
       destroyTime: decode(json['destroyTime'], Timestamp.fromJson),
-      state: decode(json['state'], SecretVersion$State.fromJson),
+      state: decode(json['state'], SecretVersion_State.fromJson),
       replicationStatus:
           decode(json['replicationStatus'], ReplicationStatus.fromJson),
       etag: json['etag'],
@@ -512,34 +512,34 @@ class SecretVersion extends Message {
 /// The state of a
 /// `SecretVersion`, indicating if
 /// it can be accessed.
-class SecretVersion$State extends Enum {
+class SecretVersion_State extends Enum {
   /// Not specified. This value is unused and invalid.
-  static const stateUnspecified = SecretVersion$State('STATE_UNSPECIFIED');
+  static const stateUnspecified = SecretVersion_State('STATE_UNSPECIFIED');
 
   /// The `SecretVersion` may be
   /// accessed.
-  static const enabled = SecretVersion$State('ENABLED');
+  static const enabled = SecretVersion_State('ENABLED');
 
   /// The `SecretVersion` may not
   /// be accessed, but the secret data is still available and can be placed
   /// back into the
   /// `ENABLED`
   /// state.
-  static const disabled = SecretVersion$State('DISABLED');
+  static const disabled = SecretVersion_State('DISABLED');
 
   /// The `SecretVersion` is
   /// destroyed and the secret data is no longer stored. A version may not
   /// leave this state once entered.
-  static const destroyed = SecretVersion$State('DESTROYED');
+  static const destroyed = SecretVersion_State('DESTROYED');
 
-  const SecretVersion$State(super.value);
+  const SecretVersion_State(super.value);
 
-  factory SecretVersion$State.fromJson(String json) =>
-      SecretVersion$State(json);
+  factory SecretVersion_State.fromJson(String json) =>
+      SecretVersion_State(json);
 
   @override
   bool operator ==(Object other) =>
-      other is SecretVersion$State && value == other.value;
+      other is SecretVersion_State && value == other.value;
 
   @override
   String toString() => 'State.$value';
@@ -552,11 +552,11 @@ class Replication extends Message {
 
   /// The `Secret` will automatically be
   /// replicated without any restrictions.
-  final Replication$Automatic? automatic;
+  final Replication_Automatic? automatic;
 
   /// The `Secret` will only be
   /// replicated into the locations specified.
-  final Replication$UserManaged? userManaged;
+  final Replication_UserManaged? userManaged;
 
   Replication({
     this.automatic,
@@ -565,9 +565,9 @@ class Replication extends Message {
 
   factory Replication.fromJson(Map<String, dynamic> json) {
     return Replication(
-      automatic: decode(json['automatic'], Replication$Automatic.fromJson),
+      automatic: decode(json['automatic'], Replication_Automatic.fromJson),
       userManaged:
-          decode(json['userManaged'], Replication$UserManaged.fromJson),
+          decode(json['userManaged'], Replication_UserManaged.fromJson),
     );
   }
 
@@ -586,7 +586,7 @@ class Replication extends Message {
 /// A replication policy that replicates the
 /// `Secret` payload without any
 /// restrictions.
-class Replication$Automatic extends Message {
+class Replication_Automatic extends Message {
   static const String fullyQualifiedName =
       'google.cloud.secretmanager.v1.Replication.Automatic';
 
@@ -601,12 +601,12 @@ class Replication$Automatic extends Message {
   /// `SecretVersions`.
   final CustomerManagedEncryption? customerManagedEncryption;
 
-  Replication$Automatic({
+  Replication_Automatic({
     this.customerManagedEncryption,
   }) : super(fullyQualifiedName);
 
-  factory Replication$Automatic.fromJson(Map<String, dynamic> json) {
-    return Replication$Automatic(
+  factory Replication_Automatic.fromJson(Map<String, dynamic> json) {
+    return Replication_Automatic(
       customerManagedEncryption: decode(json['customerManagedEncryption'],
           CustomerManagedEncryption.fromJson),
     );
@@ -628,7 +628,7 @@ class Replication$Automatic extends Message {
 /// `Secret` payload into the locations
 /// specified in
 /// `Replication.UserManaged.replicas`
-class Replication$UserManaged extends Message {
+class Replication_UserManaged extends Message {
   static const String fullyQualifiedName =
       'google.cloud.secretmanager.v1.Replication.UserManaged';
 
@@ -636,16 +636,16 @@ class Replication$UserManaged extends Message {
   /// `Secret`.
   ///
   /// Cannot be empty.
-  final List<Replication$UserManaged$Replica>? replicas;
+  final List<Replication_UserManaged_Replica>? replicas;
 
-  Replication$UserManaged({
+  Replication_UserManaged({
     this.replicas,
   }) : super(fullyQualifiedName);
 
-  factory Replication$UserManaged.fromJson(Map<String, dynamic> json) {
-    return Replication$UserManaged(
+  factory Replication_UserManaged.fromJson(Map<String, dynamic> json) {
+    return Replication_UserManaged(
       replicas: decodeList(
-          json['replicas'], Replication$UserManaged$Replica.fromJson),
+          json['replicas'], Replication_UserManaged_Replica.fromJson),
     );
   }
 
@@ -662,7 +662,7 @@ class Replication$UserManaged extends Message {
 
 /// Represents a Replica for this
 /// `Secret`.
-class Replication$UserManaged$Replica extends Message {
+class Replication_UserManaged_Replica extends Message {
   static const String fullyQualifiedName =
       'google.cloud.secretmanager.v1.Replication.UserManaged.Replica';
 
@@ -681,13 +681,13 @@ class Replication$UserManaged$Replica extends Message {
   /// `SecretVersions`.
   final CustomerManagedEncryption? customerManagedEncryption;
 
-  Replication$UserManaged$Replica({
+  Replication_UserManaged_Replica({
     this.location,
     this.customerManagedEncryption,
   }) : super(fullyQualifiedName);
 
-  factory Replication$UserManaged$Replica.fromJson(Map<String, dynamic> json) {
-    return Replication$UserManaged$Replica(
+  factory Replication_UserManaged_Replica.fromJson(Map<String, dynamic> json) {
+    return Replication_UserManaged_Replica(
       location: json['location'],
       customerManagedEncryption: decode(json['customerManagedEncryption'],
           CustomerManagedEncryption.fromJson),
@@ -772,7 +772,7 @@ class ReplicationStatus extends Message {
   /// Only populated if the parent
   /// `Secret` has an automatic
   /// replication policy.
-  final ReplicationStatus$AutomaticStatus? automatic;
+  final ReplicationStatus_AutomaticStatus? automatic;
 
   /// Describes the replication status of a
   /// `SecretVersion` with
@@ -781,7 +781,7 @@ class ReplicationStatus extends Message {
   /// Only populated if the parent
   /// `Secret` has a user-managed
   /// replication policy.
-  final ReplicationStatus$UserManagedStatus? userManaged;
+  final ReplicationStatus_UserManagedStatus? userManaged;
 
   ReplicationStatus({
     this.automatic,
@@ -791,9 +791,9 @@ class ReplicationStatus extends Message {
   factory ReplicationStatus.fromJson(Map<String, dynamic> json) {
     return ReplicationStatus(
       automatic:
-          decode(json['automatic'], ReplicationStatus$AutomaticStatus.fromJson),
+          decode(json['automatic'], ReplicationStatus_AutomaticStatus.fromJson),
       userManaged: decode(
-          json['userManaged'], ReplicationStatus$UserManagedStatus.fromJson),
+          json['userManaged'], ReplicationStatus_UserManagedStatus.fromJson),
     );
   }
 
@@ -815,7 +815,7 @@ class ReplicationStatus extends Message {
 ///
 /// Only populated if the parent `Secret`
 /// has an automatic replication policy.
-class ReplicationStatus$AutomaticStatus extends Message {
+class ReplicationStatus_AutomaticStatus extends Message {
   static const String fullyQualifiedName =
       'google.cloud.secretmanager.v1.ReplicationStatus.AutomaticStatus';
 
@@ -824,13 +824,13 @@ class ReplicationStatus$AutomaticStatus extends Message {
   /// populated if customer-managed encryption is used.
   final CustomerManagedEncryptionStatus? customerManagedEncryption;
 
-  ReplicationStatus$AutomaticStatus({
+  ReplicationStatus_AutomaticStatus({
     this.customerManagedEncryption,
   }) : super(fullyQualifiedName);
 
-  factory ReplicationStatus$AutomaticStatus.fromJson(
+  factory ReplicationStatus_AutomaticStatus.fromJson(
       Map<String, dynamic> json) {
-    return ReplicationStatus$AutomaticStatus(
+    return ReplicationStatus_AutomaticStatus(
       customerManagedEncryption: decode(json['customerManagedEncryption'],
           CustomerManagedEncryptionStatus.fromJson),
     );
@@ -854,23 +854,23 @@ class ReplicationStatus$AutomaticStatus extends Message {
 ///
 /// Only populated if the parent `Secret`
 /// has a user-managed replication policy.
-class ReplicationStatus$UserManagedStatus extends Message {
+class ReplicationStatus_UserManagedStatus extends Message {
   static const String fullyQualifiedName =
       'google.cloud.secretmanager.v1.ReplicationStatus.UserManagedStatus';
 
   /// Output only. The list of replica statuses for the
   /// `SecretVersion`.
-  final List<ReplicationStatus$UserManagedStatus$ReplicaStatus>? replicas;
+  final List<ReplicationStatus_UserManagedStatus_ReplicaStatus>? replicas;
 
-  ReplicationStatus$UserManagedStatus({
+  ReplicationStatus_UserManagedStatus({
     this.replicas,
   }) : super(fullyQualifiedName);
 
-  factory ReplicationStatus$UserManagedStatus.fromJson(
+  factory ReplicationStatus_UserManagedStatus.fromJson(
       Map<String, dynamic> json) {
-    return ReplicationStatus$UserManagedStatus(
+    return ReplicationStatus_UserManagedStatus(
       replicas: decodeList(json['replicas'],
-          ReplicationStatus$UserManagedStatus$ReplicaStatus.fromJson),
+          ReplicationStatus_UserManagedStatus_ReplicaStatus.fromJson),
     );
   }
 
@@ -887,7 +887,7 @@ class ReplicationStatus$UserManagedStatus extends Message {
 
 /// Describes the status of a user-managed replica for the
 /// `SecretVersion`.
-class ReplicationStatus$UserManagedStatus$ReplicaStatus extends Message {
+class ReplicationStatus_UserManagedStatus_ReplicaStatus extends Message {
   static const String fullyQualifiedName =
       'google.cloud.secretmanager.v1.ReplicationStatus.UserManagedStatus.ReplicaStatus';
 
@@ -900,14 +900,14 @@ class ReplicationStatus$UserManagedStatus$ReplicaStatus extends Message {
   /// populated if customer-managed encryption is used.
   final CustomerManagedEncryptionStatus? customerManagedEncryption;
 
-  ReplicationStatus$UserManagedStatus$ReplicaStatus({
+  ReplicationStatus_UserManagedStatus_ReplicaStatus({
     this.location,
     this.customerManagedEncryption,
   }) : super(fullyQualifiedName);
 
-  factory ReplicationStatus$UserManagedStatus$ReplicaStatus.fromJson(
+  factory ReplicationStatus_UserManagedStatus_ReplicaStatus.fromJson(
       Map<String, dynamic> json) {
-    return ReplicationStatus$UserManagedStatus$ReplicaStatus(
+    return ReplicationStatus_UserManagedStatus_ReplicaStatus(
       location: json['location'],
       customerManagedEncryption: decode(json['customerManagedEncryption'],
           CustomerManagedEncryptionStatus.fromJson),
diff --git a/generator/dart/generated/google_cloud_type/lib/type.dart b/generator/dart/generated/google_cloud_type/lib/type.dart
index 6c48c20dd2..bf0736db0e 100755
--- a/generator/dart/generated/google_cloud_type/lib/type.dart
+++ b/generator/dart/generated/google_cloud_type/lib/type.dart
@@ -896,7 +896,7 @@ class PhoneNumber extends Message {
   ///
   /// Reference(s):
   ///  - https://en.wikipedia.org/wiki/Short_code
-  final PhoneNumber$ShortCode? shortCode;
+  final PhoneNumber_ShortCode? shortCode;
 
   /// The phone number's extension. The extension is not standardized in ITU
   /// recommendations, except for being defined as a series of numbers with a
@@ -918,7 +918,7 @@ class PhoneNumber extends Message {
   factory PhoneNumber.fromJson(Map<String, dynamic> json) {
     return PhoneNumber(
       e164Number: json['e164Number'],
-      shortCode: decode(json['shortCode'], PhoneNumber$ShortCode.fromJson),
+      shortCode: decode(json['shortCode'], PhoneNumber_ShortCode.fromJson),
       extension: json['extension'],
     );
   }
@@ -951,7 +951,7 @@ class PhoneNumber extends Message {
 /// dialable, which means the same short code can exist in different regions,
 /// with different usage and pricing, even if those regions share the same
 /// country calling code (e.g. US and CA).
-class PhoneNumber$ShortCode extends Message {
+class PhoneNumber_ShortCode extends Message {
   static const String fullyQualifiedName = 'google.type.PhoneNumber.ShortCode';
 
   /// Required. The BCP-47 region code of the location where calls to this
@@ -965,13 +965,13 @@ class PhoneNumber$ShortCode extends Message {
   /// calling code, e.g. "611".
   final String? number;
 
-  PhoneNumber$ShortCode({
+  PhoneNumber_ShortCode({
     this.regionCode,
     this.number,
   }) : super(fullyQualifiedName);
 
-  factory PhoneNumber$ShortCode.fromJson(Map<String, dynamic> json) {
-    return PhoneNumber$ShortCode(
+  factory PhoneNumber_ShortCode.fromJson(Map<String, dynamic> json) {
+    return PhoneNumber_ShortCode(
       regionCode: json['regionCode'],
       number: json['number'],
     );
diff --git a/generator/dart/tests/test/encoding_test.dart b/generator/dart/tests/test/encoding_test.dart
index 0723c8626e..ba6bfe7241 100644
--- a/generator/dart/tests/test/encoding_test.dart
+++ b/generator/dart/tests/test/encoding_test.dart
@@ -104,11 +104,11 @@ void main() {
   test('QuotaFailure', () {
     final expected = QuotaFailure(
       violations: [
-        QuotaFailure$Violation(
+        QuotaFailure_Violation(
           subject: 'project:foo',
           description: 'Limit exceeded',
         ),
-        QuotaFailure$Violation(
+        QuotaFailure_Violation(
           subject: 'clientip:1.2.3.4',
           description: 'Service disabled',
         ),
diff --git a/generator/internal/dart/dart.go b/generator/internal/dart/dart.go
index dc71739b81..7cb68174c1 100644
--- a/generator/internal/dart/dart.go
+++ b/generator/internal/dart/dart.go
@@ -53,6 +53,15 @@ var usesCustomEncoding = map[string]string{
 	".google.protobuf.UInt64Value": "",
 }
 
+// Used to concatenate a message and a child message.
+var nestedMessageChar = "_"
+
+// Used to concatenate a message and a child enum.
+var nestedEnumChar = "_"
+
+// Appended to a name to avoid conflicting with a Dart identifier.
+var deconflictChar = "$"
+
 // Dart reserved words.
 //
 // This blocklist includes words that can never be used as an identifier as well
@@ -105,12 +114,12 @@ func messageName(m *api.Message) string {
 	if m.Parent == nil {
 		// For top-most symbols, check for conflicts with reserved names.
 		if _, hasConflict := reservedNames[name]; hasConflict {
-			return name + "$"
+			return name + deconflictChar
 		} else {
 			return name
 		}
 	} else {
-		return messageName(m.Parent) + "$" + name
+		return messageName(m.Parent) + nestedMessageChar + name
 	}
 }
 
@@ -122,22 +131,23 @@ func qualifiedName(m *api.Message) string {
 func fieldName(field *api.Field) string {
 	name := strcase.ToLowerCamel(field.Name)
 	if _, hasConflict := reservedNames[name]; hasConflict {
-		name = name + "$"
+		name = name + deconflictChar
 	}
 	return name
 }
 
 func enumName(e *api.Enum) string {
+	name := strcase.ToCamel(e.Name)
 	if e.Parent != nil {
-		return messageName(e.Parent) + "$" + strcase.ToCamel(e.Name)
+		name = messageName(e.Parent) + nestedEnumChar + name
 	}
-	return strcase.ToCamel(e.Name)
+	return name
 }
 
 func enumValueName(e *api.EnumValue) string {
 	name := strcase.ToLowerCamel(e.Name)
 	if _, hasConflict := reservedNames[name]; hasConflict {
-		name = name + "$"
+		name = name + deconflictChar
 	}
 	return name
 }
diff --git a/generator/internal/dart/dart_test.go b/generator/internal/dart/dart_test.go
index de4748df88..b5a1296a84 100644
--- a/generator/internal/dart/dart_test.go
+++ b/generator/internal/dart/dart_test.go
@@ -43,7 +43,7 @@ func TestMessageNames(t *testing.T) {
 		want    string
 	}{
 		{message: r, want: "Replication"},
-		{message: a, want: "Replication$Automatic"},
+		{message: a, want: "Replication_Automatic"},
 		{message: f, want: "Function$"},
 		{message: sample.SecretPayload(), want: "SecretPayload"},
 	} {
@@ -95,7 +95,7 @@ func TestEnumNames(t *testing.T) {
 		wantEnum string
 	}{
 		{non_nested, "Code"},
-		{nested, "SecretVersion$State"},
+		{nested, "SecretVersion_State"},
 	} {
 		if got := enumName(test.enum); got != test.wantEnum {
 			t.Errorf("c.enumName(%q) = %q; want = %s", test.enum.Name, got, test.wantEnum)


Reviews:
user: login: coryan
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T00:31:33Z
user: login: lrhn
body: A quick look at the code suggests that every prefixed name would be unique without the prefix too. I would consider omitting prefixes that are not necessary to avoid a conflict. No user was ever happier because they could see or had to write an extra prefix. Longnamesarelong.

I would try to aim for an API that felt like Dart, so I'd never have a prefix on a type in Dart if it doesn't conflict with another name in the same library. 
(Unless there is some strategic, long-term reason not to, or there is some bueraucratic reason names must match the proto naming, even though that was never really intended for human consumption. Or expected a language with nested namespaces.)
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-10T12:43:04Z
user: login: coryan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T13:17:34Z
user: login: devoncarew
body: > From a readability perspective, I like _ much better than $, and would change every $ to _.
> ...
> It's not clear, because $ looks like a letter. It's very easily overlooked, and you have to look harder than I want to, just to see that it's there. The _ is a very visible divider.
But neither is good Dart style.

I'm going to run some numbers for the APIs to see about common names, % of conflicts we'd see and such. I suspect we will need to concatenate things for namespacing but would still like to see what the numbers say.

state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T15:30:43Z
user: login: coryan
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T12:18:02Z

Review comments:
diff_hunk: @@ -327,33 +327,33 @@ class Function$ extends Message {
 }
 
 /// Describes the current state of the function.
-class Function$$State extends Enum {
+class Function$State extends Enum {
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: lrhn
body: Is the prefix *needed*?

Could this just be `State` without any prefix, without having a conflict in *this* package. Or even this library.
Otherwise `FunctionState` is reasonable too. 

Those are the two names I'd use if writing Dart code manually.

created_at: 2025-04-10T12:01:36Z
author_association: NONE
diff_hunk: @@ -327,33 +327,33 @@ class Function$ extends Message {
 }
 
 /// Describes the current state of the function.
-class Function$$State extends Enum {
+class Function$State extends Enum {
   /// Not specified. Invalid state.
-  static const stateUnspecified = Function$$State('STATE_UNSPECIFIED');
+  static const stateUnspecified = Function$State('STATE_UNSPECIFIED');
 
   /// Function has been successfully deployed and is serving.
-  static const active = Function$$State('ACTIVE');
+  static const active = Function$State('ACTIVE');
 
   /// Function deployment failed and the function is not serving.
-  static const failed = Function$$State('FAILED');
+  static const failed = Function$State('FAILED');
 
   /// Function is being created or updated.
-  static const deploying = Function$$State('DEPLOYING');
+  static const deploying = Function$State('DEPLOYING');
 
   /// Function is being deleted.
-  static const deleting = Function$$State('DELETING');
+  static const deleting = Function$State('DELETING');
 
   /// Function deployment failed and the function serving state is undefined.
   /// The function should be updated or deleted to move it out of this state.
-  static const unknown = Function$$State('UNKNOWN');
+  static const unknown = Function$State('UNKNOWN');
 
-  const Function$$State(super.value);
+  const Function$State(super.value);
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: lrhn
body: If this is intended as an enum, consider either making it an `enum`, or at least making the constructor private, so no more instances will be created.
Then you can use `identical` in `operator==`.
(But if you have to accept any string value in `fromJson`, you can't do that. Must you accept any string value?)

created_at: 2025-04-10T12:03:01Z
author_association: NONE
diff_hunk: @@ -327,33 +327,33 @@ class Function$ extends Message {
 }
 
 /// Describes the current state of the function.
-class Function$$State extends Enum {
+class Function$State extends Enum {
   /// Not specified. Invalid state.
-  static const stateUnspecified = Function$$State('STATE_UNSPECIFIED');
+  static const stateUnspecified = Function$State('STATE_UNSPECIFIED');
 
   /// Function has been successfully deployed and is serving.
-  static const active = Function$$State('ACTIVE');
+  static const active = Function$State('ACTIVE');
 
   /// Function deployment failed and the function is not serving.
-  static const failed = Function$$State('FAILED');
+  static const failed = Function$State('FAILED');
 
   /// Function is being created or updated.
-  static const deploying = Function$$State('DEPLOYING');
+  static const deploying = Function$State('DEPLOYING');
 
   /// Function is being deleted.
-  static const deleting = Function$$State('DELETING');
+  static const deleting = Function$State('DELETING');
 
   /// Function deployment failed and the function serving state is undefined.
   /// The function should be updated or deleted to move it out of this state.
-  static const unknown = Function$$State('UNKNOWN');
+  static const unknown = Function$State('UNKNOWN');
 
-  const Function$$State(super.value);
+  const Function$State(super.value);
 
-  factory Function$$State.fromJson(String json) => Function$$State(json);
+  factory Function$State.fromJson(String json) => Function$State(json);
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: lrhn
body: (Could reuse existing instances, instead of creating a new one with the same value.)
created_at: 2025-04-10T12:05:31Z
author_association: NONE
diff_hunk: @@ -1320,7 +1320,7 @@ class SecretVolume extends Message {
 }
 
 /// Configuration for a single version.
-class SecretVolume$SecretVersion extends Message {
+class SecretVolume_SecretVersion extends Message {
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: lrhn
body: Same: Could this be called just `SecretVersion`? Or `SecretVolumeVersion`?
If there is no other `SecretVersion` in scope, then there is no conflict.
(Or even just have a `typedef SecretVersion = SecretVolume_SecretVersion;`.)

Do we fear that a later version will add another `SecretVersion` type, and we'll get a conflict at that time, and it'll be breaking to remove the shorthcut?
created_at: 2025-04-10T12:08:01Z
author_association: NONE
diff_hunk: @@ -279,7 +279,7 @@ class Function$ extends Message {
       buildConfig: decode(json['buildConfig'], BuildConfig.fromJson),
       serviceConfig: decode(json['serviceConfig'], ServiceConfig.fromJson),
       eventTrigger: decode(json['eventTrigger'], EventTrigger.fromJson),
-      state: decode(json['state'], Function$$State.fromJson),
+      state: decode(json['state'], Function$State.fromJson),
       updateTime: decode(json['updateTime'], Timestamp.fromJson),
       labels: (json['labels'] as Map?)?.cast(),
       stateMessages: decodeList(json['stateMessages'], StateMessage.fromJson),
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: lrhn
body: (Drive-by-comment: The ` if (buildConfig != null) 'buildConfig': buildConfig!.toJson(),` could use a pattern to avoid the extra `!`.
`if (buildConfig case final value?) 'buildConfig': value.toJson(),`. Can use longer names than `value`, or something as short as `v`, but it shouldn't matter.)
created_at: 2025-04-10T12:41:52Z
author_association: NONE
diff_hunk: @@ -327,33 +327,33 @@ class Function$ extends Message {
 }
 
 /// Describes the current state of the function.
-class Function$$State extends Enum {
+class Function$State extends Enum {
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: coryan
body: > Is the prefix _needed_?

Maybe not now. Services evolve, if somebody adds a top-level `State` message then the prefix becomes needed and now you have a breaking change to deal with.

> Could this just be `State` without any prefix, without having a conflict in _this_ package. Or even this library. Otherwise `FunctionState` is reasonable too.
> 
> Those are the two names I'd use if writing Dart code manually.

OTOH, we need to create names that are stable under additions to the service definition. Without introducing breaking changes when the service makes a non-breaking change.

created_at: 2025-04-10T13:17:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -279,7 +279,7 @@ class Function$ extends Message {
       buildConfig: decode(json['buildConfig'], BuildConfig.fromJson),
       serviceConfig: decode(json['serviceConfig'], ServiceConfig.fromJson),
       eventTrigger: decode(json['eventTrigger'], EventTrigger.fromJson),
-      state: decode(json['state'], Function$$State.fromJson),
+      state: decode(json['state'], Function$State.fromJson),
       updateTime: decode(json['updateTime'], Timestamp.fromJson),
       labels: (json['labels'] as Map?)?.cast(),
       stateMessages: decodeList(json['stateMessages'], StateMessage.fromJson),
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: devoncarew
body: I'm going to mostly re-write the json decoding logic. There are a few corner cases that we need to handle, and I understand it well enough now that I can simplify both the code generation for this as well as the generated code (mostly using specific functions to decode from json and have the code generator just select the right function for the data type).
created_at: 2025-04-10T15:15:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -327,33 +327,33 @@ class Function$ extends Message {
 }
 
 /// Describes the current state of the function.
-class Function$$State extends Enum {
+class Function$State extends Enum {
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: devoncarew
body: I think the two goals are:

- having an ergonomic, idiomatic library
- not introducing unnecessary breaking api changes as a result of generation (not have the generator introduce a breaking change which isn't because of an upstream api breaking change)

Possibly another goal related to the 2nd item is that the delta in a generated library should be roughly proportional to an upstream API delta.

created_at: 2025-04-10T15:19:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -327,33 +327,33 @@ class Function$ extends Message {
 }
 
 /// Describes the current state of the function.
-class Function$$State extends Enum {
+class Function$State extends Enum {
   /// Not specified. Invalid state.
-  static const stateUnspecified = Function$$State('STATE_UNSPECIFIED');
+  static const stateUnspecified = Function$State('STATE_UNSPECIFIED');
 
   /// Function has been successfully deployed and is serving.
-  static const active = Function$$State('ACTIVE');
+  static const active = Function$State('ACTIVE');
 
   /// Function deployment failed and the function is not serving.
-  static const failed = Function$$State('FAILED');
+  static const failed = Function$State('FAILED');
 
   /// Function is being created or updated.
-  static const deploying = Function$$State('DEPLOYING');
+  static const deploying = Function$State('DEPLOYING');
 
   /// Function is being deleted.
-  static const deleting = Function$$State('DELETING');
+  static const deleting = Function$State('DELETING');
 
   /// Function deployment failed and the function serving state is undefined.
   /// The function should be updated or deleted to move it out of this state.
-  static const unknown = Function$$State('UNKNOWN');
+  static const unknown = Function$State('UNKNOWN');
 
-  const Function$$State(super.value);
+  const Function$State(super.value);
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: devoncarew
body: Yeah, I think one requirement is that the set of enum values we have to deal with isn't closed. We may get an enum value over the wire that we didn't know about at generation time. We'd need to:

- not throw an exception
- possibly allow the user to still reason about that unexpected value
- probably be able to round-trip the same enum value back to the server (if contained in some parent object)

created_at: 2025-04-10T15:22:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1320,7 +1320,7 @@ class SecretVolume extends Message {
 }
 
 /// Configuration for a single version.
-class SecretVolume$SecretVersion extends Message {
+class SecretVolume_SecretVersion extends Message {
path: generator/dart/generated/google_cloud_functions_v2/lib/cloudfunctions.dart
user: login: devoncarew
body: More that I'd fear multiple enums in a library (all appropriately nested in messages), called `Type`, or `Status`, or something else very common.
created_at: 2025-04-10T15:24:08Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-04-09T21:38:26Z
body: ## [Codecov](https://app.codecov.io/gh/googleapis/google-cloud-rust/pull/1762?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=googleapis) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.82%. Comparing base [(`91334d8`)](https://app.codecov.io/gh/googleapis/google-cloud-rust/commit/91334d80695a32a4afd321702e203b870f6292aa?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=googleapis) to head [(`0a7cc22`)](https://app.codecov.io/gh/googleapis/google-cloud-rust/commit/0a7cc22d5a621fe8afe2489188aa061b3ebc61a6?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=googleapis).
> Report is 1 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #1762   +/-   ##
=======================================
  Coverage   95.82%   95.82%           
=======================================
  Files          53       53           
  Lines        1989     1989           
=======================================
  Hits         1906     1906           
  Misses         83       83           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/googleapis/google-cloud-rust/pull/1762?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=googleapis).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=googleapis).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: lrhn
created_at: 2025-04-10T12:43:41Z
body: From a readability perspective, I like `_` much better than `$`, and would change every `$` to `_`.

>  because then you can easily see that the `EnumQux` enum is owned by the

It's not clear, because `$` looks like a letter. It's very easily overlooked, and you have to look harder than I want to, just to see that it's there. The `_` is a very visible divider.
But neither is good *Dart* style.
author_association: NONE
user: login: devoncarew
created_at: 2025-04-11T01:56:08Z
body: Yeah, there are a lot of name collisions. Just for the APIs that the rust backend is generating, if we don't do any name concatenation, we see hundreds (~1,000?) of collisions; https://gist.github.com/devoncarew/fc8844dce25a3790f4a37b91b22a43e8.

```
google.iam.credentials.v1.iamcredentials
  State count 4
  SubstitutionsEntry count 3
google.firestore.v1
  Operator count 3
  FieldsEntry count 2
  LabelsEntry count 3
google.iam.v3.iam
  AnnotationsEntry count 2
google.cloud.tpu.v2.tpu
  State count 2
google.cloud.managedidentities.v1.managedidentities
  State count 2
google.cloud.bigquery.reservation.v1.bigqueryreservation
  State count 2
google.cloud.video.stitcher.v1.videostitcher
  GamSettings count 2
  State count 2
...
```

If we concatenate just a symbol and its immediate parent - `MyMessage_MyEnum` - but don't include any potential parent message of `MyMessage`, we still see collisions:

```
google.cloud.optimization.v1.cloudoptimization
  BreakRequest_BreakRule count 2
  FrequencyConstraint_BreakRule count 2
google.cloud.dialogflow.v2.dialogflow
  TextSectionsEntry_Summary count 2
google.cloud.recommender.logging.v1.recommender
  OrderedCodeBytes_Encoding count 2
google.cloud.discoveryengine.v1.discoveryengine
  DocumentMetadata_ChunkInfo count 3
  ChunkInfo_SearchResult count 2
google.cloud.networkservices.v1.networkservices
  Delay_FaultInjectionPolicy count 2
  Abort_FaultInjectionPolicy count 2
google.cloud.aiplatform.v1.aiplatform
  RagResource_VertexRagStore count 2
  GoalType_MetricSpec count 2
google.devtools.artifactregistry.v1.artifactregistry
  RepositoryBase_PublicRepository count 2
```

That's about a dozen collisions in ~180 APIs. So not a large number, but they still exist. There would be ways to generate this that are predictable and don't introduce unnecessary breaking changes.

I'm not certain it's a strict improvement though to just use the last two proto member names when building a symbol name. It might be odd for the first part of the name to fall off as you generate child elements. I'll likely keep the full concatenation for this PR.

author_association: CONTRIBUTOR
user: login: devoncarew
created_at: 2025-04-11T02:47:24Z
body: I landed on underscore as the concatenation char for both messages and enums and `$` as the char to deconflict w/ a Dart keyword.

- `MessageFoo_MessageBar_EnumBaz`
- `Function$_State`

author_association: CONTRIBUTOR