[pigeon] Add usage docs to generated Dart event channel methods (#11894)

The generated event-channel method creates a new `EventChannel` each time it is called, but nothing in the generated code documented that — making it easy to call repeatedly for the same instance, or to assume the returned stream is single-subscription. This implements the "definitely" part of the linked issue:

> Definitely add docs to the generated code, indicated both that it shouldn't be called multiple times for the same instance, and that the returned stream is a broadcast stream.

Each generated event-channel method now gets a usage doc comment:

```dart
/// Returns a broadcast [Stream] of events from the `streamEvents` event channel.
///
/// Each call to this method creates a new [EventChannel], so it should
/// not be called multiple times for the same `instanceName`. To deliver
/// events to multiple listeners, call this method once and listen to the
/// returned broadcast stream multiple times instead.
```

While there, this also emits the user's own documentation comments on event channel methods — previously only the API-level comments were emitted and per-method comments were silently dropped. The two are combined via the existing `generatorComments` mechanism in `addDocumentationComments`, which already handles user-comment/generator-comment separation.

The wrapper-object and renaming ideas from the issue are intentionally not addressed here, per the discussion — those are design decisions; this PR is scoped to the documentation gap.

Checked-in generated files containing event channels (`example/app` and `shared_test_plugin_code`) are regenerated. The new generator test verifies both the user comments and the usage docs are emitted directly above the generated method, and fails without the generator change.

Fixes https://github.com/flutter/flutter/issues/177776

## Pre-Review Checklist

Note: the multi-language auto-formatter step of `tool/generate.dart` could not run fully on this machine (missing clang-format and related binaries); only Dart outputs changed, and those were formatted with `dart format`. If CI's format check flags anything, I'll address it.
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index a87e4e9..803f62b 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 27.1.1
+
+* [dart] Adds usage documentation to generated event channel methods, and
+  emits the user's documentation comments on them.
+
 ## 27.1.0
 
 * [swift] Adds `CaseIterable` conformance to generated enums.
diff --git a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart
index 28217b3..d13b926 100644
--- a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart
+++ b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart
@@ -188,6 +188,12 @@
 
 const StandardMethodCodec pigeonMethodCodec = StandardMethodCodec(_PigeonCodec());
 
+/// Returns a broadcast [Stream] of events from the `streamEvents` event channel.
+///
+/// Each call to this method creates a new [EventChannel], so it should
+/// not be called multiple times for the same `instanceName`. To deliver
+/// events to multiple listeners, call this method once and listen to the
+/// returned broadcast stream multiple times instead.
 Stream<PlatformEvent> streamEvents({String instanceName = ''}) {
   if (instanceName.isNotEmpty) {
     instanceName = '.$instanceName';
diff --git a/packages/pigeon/lib/src/dart/dart_generator.dart b/packages/pigeon/lib/src/dart/dart_generator.dart
index ae0614a..3218103 100644
--- a/packages/pigeon/lib/src/dart/dart_generator.dart
+++ b/packages/pigeon/lib/src/dart/dart_generator.dart
@@ -632,6 +632,19 @@
     indent.newln();
     addDocumentationComments(indent, api.documentationComments, docCommentSpec);
     for (final Method func in api.methods) {
+      addDocumentationComments(
+        indent,
+        func.documentationComments,
+        docCommentSpec,
+        generatorComments: <String>[
+          'Returns a broadcast [Stream] of events from the `${func.name}` event channel.',
+          '',
+          'Each call to this method creates a new [EventChannel], so it should',
+          'not be called multiple times for the same `instanceName`. To deliver',
+          'events to multiple listeners, call this method once and listen to the',
+          'returned broadcast stream multiple times instead.',
+        ],
+      );
       indent.format('''
       Stream<${func.returnType.baseName}> ${func.name}(${_getMethodParameterSignature(func.parameters, addTrailingComma: true)} {String instanceName = ''}) {
         if (instanceName.isNotEmpty) {
diff --git a/packages/pigeon/lib/src/generator_tools.dart b/packages/pigeon/lib/src/generator_tools.dart
index 4cc20cf..dbc56d4 100644
--- a/packages/pigeon/lib/src/generator_tools.dart
+++ b/packages/pigeon/lib/src/generator_tools.dart
@@ -15,7 +15,7 @@
 /// The current version of pigeon.
 ///
 /// This must match the version in pubspec.yaml.
-const String pigeonVersion = '27.1.0';
+const String pigeonVersion = '27.1.1';
 
 /// Default plugin package name.
 const String defaultPluginPackageName = 'dev.flutter.pigeon';
diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart
index 48d008b..9602837 100644
--- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart
+++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart
@@ -663,6 +663,12 @@
 
 const StandardMethodCodec pigeonMethodCodec = StandardMethodCodec(_PigeonCodec());
 
+/// Returns a broadcast [Stream] of events from the `streamInts` event channel.
+///
+/// Each call to this method creates a new [EventChannel], so it should
+/// not be called multiple times for the same `instanceName`. To deliver
+/// events to multiple listeners, call this method once and listen to the
+/// returned broadcast stream multiple times instead.
 Stream<int> streamInts({String instanceName = ''}) {
   if (instanceName.isNotEmpty) {
     instanceName = '.$instanceName';
@@ -676,6 +682,12 @@
   });
 }
 
+/// Returns a broadcast [Stream] of events from the `streamEvents` event channel.
+///
+/// Each call to this method creates a new [EventChannel], so it should
+/// not be called multiple times for the same `instanceName`. To deliver
+/// events to multiple listeners, call this method once and listen to the
+/// returned broadcast stream multiple times instead.
 Stream<PlatformEvent> streamEvents({String instanceName = ''}) {
   if (instanceName.isNotEmpty) {
     instanceName = '.$instanceName';
@@ -689,6 +701,12 @@
   });
 }
 
+/// Returns a broadcast [Stream] of events from the `streamConsistentNumbers` event channel.
+///
+/// Each call to this method creates a new [EventChannel], so it should
+/// not be called multiple times for the same `instanceName`. To deliver
+/// events to multiple listeners, call this method once and listen to the
+/// returned broadcast stream multiple times instead.
 Stream<int> streamConsistentNumbers({String instanceName = ''}) {
   if (instanceName.isNotEmpty) {
     instanceName = '.$instanceName';
diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_without_classes_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_without_classes_tests.gen.dart
index 1bc0680..d6c39f9 100644
--- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_without_classes_tests.gen.dart
+++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_without_classes_tests.gen.dart
@@ -36,6 +36,12 @@
 
 const StandardMethodCodec pigeonMethodCodec = StandardMethodCodec(_PigeonCodec());
 
+/// Returns a broadcast [Stream] of events from the `streamIntsAgain` event channel.
+///
+/// Each call to this method creates a new [EventChannel], so it should
+/// not be called multiple times for the same `instanceName`. To deliver
+/// events to multiple listeners, call this method once and listen to the
+/// returned broadcast stream multiple times instead.
 Stream<int> streamIntsAgain({String instanceName = ''}) {
   if (instanceName.isNotEmpty) {
     instanceName = '.$instanceName';
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index 65afaca..bf3b956 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
 repository: https://github.com/flutter/packages/tree/main/packages/pigeon
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22
-version: 27.1.0 # This must match the version in lib/src/generator_tools.dart
+version: 27.1.1 # This must match the version in lib/src/generator_tools.dart
 
 environment:
   sdk: ^3.10.0
diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart
index 695b9a9..dce12d0 100644
--- a/packages/pigeon/test/dart_generator_test.dart
+++ b/packages/pigeon/test/dart_generator_test.dart
@@ -79,6 +79,46 @@
     expect(code, contains('  two,'));
   });
 
+  test('gen event channel api with usage docs on the generated method', () {
+    final api = AstEventChannelApi(
+      name: 'EventApi',
+      methods: <Method>[
+        Method(
+          name: 'streamEvents',
+          location: ApiLocation.host,
+          returnType: const TypeDeclaration(baseName: 'int', isNullable: false),
+          parameters: <Parameter>[],
+          documentationComments: <String>[' An example event stream.'],
+        ),
+      ],
+    );
+    final root = Root(apis: <Api>[api], classes: <Class>[], enums: <Enum>[]);
+    final sink = StringBuffer();
+    const generator = DartGenerator();
+    generator.generate(
+      const InternalDartOptions(ignoreLints: false),
+      root,
+      sink,
+      dartPackageName: DEFAULT_PACKAGE_NAME,
+    );
+    final code = sink.toString();
+    expect(code, contains('Stream<int> streamEvents('));
+    // The user's own documentation comments are emitted.
+    expect(code, contains('/// An example event stream.'));
+    // The generated usage documentation explains the channel-owning and
+    // broadcast semantics.
+    expect(
+      code,
+      contains('/// Returns a broadcast [Stream] of events from the `streamEvents` event channel.'),
+    );
+    expect(code, contains('not be called multiple times for the same `instanceName`'));
+    // The usage documentation is attached directly above the generated method.
+    expect(
+      code.indexOf('not be called multiple times'),
+      lessThan(code.indexOf('Stream<int> streamEvents(')),
+    );
+  });
+
   test('gen one host api', () {
     final root = Root(
       apis: <Api>[