Add `UseResult` annotation to `rebuild` (#631)
This catches issues like #630 where we forgot to use return value of
`rebuild`. Since `rebuild` does not update in-place, not using the
return value is often a bug.
This adds `meta` as a dependency but it should not affect generated
code. We may also want to use `meta` in the future for things like:
- Annotating `GeneratedMessage` methods that are supposed to be used by
the generated code with `@protected`.
- Annotating generated message classes with `@sealed`. This help with
maintaining backwards compatibility when adding new members to
generated messages or to `GeneratedMessage`.
diff --git a/protobuf/lib/protobuf.dart b/protobuf/lib/protobuf.dart
index e2d5cdc..f60d5ee 100644
--- a/protobuf/lib/protobuf.dart
+++ b/protobuf/lib/protobuf.dart
@@ -11,6 +11,7 @@
import 'dart:typed_data' show TypedData, Uint8List, ByteData, Endian;
import 'package:fixnum/fixnum.dart' show Int64;
+import 'package:meta/meta.dart' show UseResult;
import 'src/protobuf/json_parsing_context.dart';
import 'src/protobuf/permissive_compare.dart';
diff --git a/protobuf/lib/src/protobuf/generated_message.dart b/protobuf/lib/src/protobuf/generated_message.dart
index c9cb0a9..6fa71d7 100644
--- a/protobuf/lib/src/protobuf/generated_message.dart
+++ b/protobuf/lib/src/protobuf/generated_message.dart
@@ -545,6 +545,8 @@
///
/// Makes a writable shallow copy of this message, applies the [updates] to
/// it, and marks the copy read-only before returning it.
+ @UseResult('[GeneratedMessageGenericExtensions.rebuild] '
+ 'does not update the message, returns a new message')
T rebuild(void Function(T) updates) {
if (!isFrozen) {
throw ArgumentError('Rebuilding only works on frozen messages.');
diff --git a/protobuf/pubspec.yaml b/protobuf/pubspec.yaml
index 3805ee8..259c8c6 100644
--- a/protobuf/pubspec.yaml
+++ b/protobuf/pubspec.yaml
@@ -11,6 +11,7 @@
dependencies:
fixnum: ^1.0.0
collection: ^1.15.0
+ meta: ^1.7.0
dev_dependencies:
test: ^1.16.0
diff --git a/protoc_plugin/test/oneof_test.dart b/protoc_plugin/test/oneof_test.dart
index de1c00a..dcd65fa 100644
--- a/protoc_plugin/test/oneof_test.dart
+++ b/protoc_plugin/test/oneof_test.dart
@@ -161,11 +161,15 @@
test('copyWith preserves oneof state', () {
var foo = Foo();
expectOneofNotSet(foo);
- var copy1 = foo.deepCopy().freeze().rebuild((_) {}) as Foo;
+ // `ignore` below to work around https://github.com/dart-lang/sdk/issues/48879
+ var copy1 =
+ foo.deepCopy().freeze().rebuild((_) {}) as Foo; // ignore: unused_result
expectOneofNotSet(copy1);
foo.first = 'oneof';
expectFirstSet(foo);
- var copy2 = foo.deepCopy().freeze().rebuild((_) {}) as Foo;
+ // `ignore` below to work around https://github.com/dart-lang/sdk/issues/48879
+ var copy2 =
+ foo.deepCopy().freeze().rebuild((_) {}) as Foo; // ignore: unused_result
expectFirstSet(copy2);
});