From 3f8a5029fbb4f79f94ade1c937826b434f335469 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 15 Apr 2022 11:42:34 -0400 Subject: [PATCH] [pigeon] Remove support for non-NNBD (#1524) Makes a breaking change to remove non-NNBD support, since it adds complexity to the generator and there's no compelling reason to continue supporting it going forward. Also updates some legacy Dart commands in scripts (dartanalyzer, dart pub run) to their modern versions. --- packages/pigeon/CHANGELOG.md | 7 +- packages/pigeon/lib/dart_generator.dart | 141 +++++++--------- packages/pigeon/lib/generator_tools.dart | 2 +- packages/pigeon/lib/pigeon_lib.dart | 6 - packages/pigeon/pubspec.yaml | 2 +- packages/pigeon/run_tests.sh | 36 ++--- packages/pigeon/test/dart_generator_test.dart | 152 +++++------------- packages/pigeon/test/pigeon_lib_test.dart | 10 +- 8 files changed, 121 insertions(+), 235 deletions(-) diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index a53b3b7adb13..97bd5dfcd805 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.0.0 + +* **BREAKING CHANGE**: Removes the `--dart_null_safety` flag. Generated Dart + now always uses nullability annotations, and thus requires Dart 2.12 or later. + ## 2.0.4 * Fixes bug where Dart `FlutterApi`s would assert that a nullable argument was nonnull. @@ -9,7 +14,7 @@ ## 2.0.2 * Fixes Java crash for nullable nested type. - + * ## 2.0.1 * Adds support for TaskQueues for serial background execution. diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 0325c29eebfa..982044cf1194 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -9,10 +9,7 @@ import 'generator_tools.dart'; /// Options that control how Dart code will be generated. class DartOptions { /// Constructor for DartOptions. - const DartOptions({this.isNullSafe = true, this.copyrightHeader}); - - /// Determines if the generated code has null safety annotations (Dart >=2.12 required). - final bool isNullSafe; + const DartOptions({this.copyrightHeader}); /// A copyright header that will get prepended to generated code. final Iterable? copyrightHeader; @@ -23,7 +20,6 @@ class DartOptions { final Iterable? copyrightHeader = map['copyrightHeader'] as Iterable?; return DartOptions( - isNullSafe: map['isNullSafe'] as bool? ?? true, copyrightHeader: copyrightHeader?.cast(), ); } @@ -32,7 +28,6 @@ class DartOptions { /// `x = DartOptions.fromMap(x.toMap())`. Map toMap() { final Map result = { - if (isNullSafe != null) 'isNullSafe': isNullSafe, if (copyrightHeader != null) 'copyrightHeader': copyrightHeader!, }; return result; @@ -102,17 +97,17 @@ void _writeCodec(Indent indent, String codecName, Api api, Root root) { } /// Creates a Dart type where all type arguments are [Objects]. -String _makeGenericTypeArguments(TypeDeclaration type, String nullTag) { +String _makeGenericTypeArguments(TypeDeclaration type) { return type.typeArguments.isNotEmpty - ? '${type.baseName}<${type.typeArguments.map((TypeDeclaration e) => 'Object$nullTag').join(', ')}>' - : _addGenericTypes(type, nullTag); + ? '${type.baseName}<${type.typeArguments.map((TypeDeclaration e) => 'Object?').join(', ')}>' + : _addGenericTypes(type); } /// Creates a `.cast<>` call for an type. Returns an empty string if the /// type has no type arguments. -String _makeGenericCastCall(TypeDeclaration type, String nullTag) { +String _makeGenericCastCall(TypeDeclaration type) { return type.typeArguments.isNotEmpty - ? '.cast<${_flattenTypeArguments(type.typeArguments, nullTag)}>()' + ? '.cast<${_flattenTypeArguments(type.typeArguments)}>()' : ''; } @@ -125,16 +120,15 @@ String _getArgumentName(int count, NamedType field) => field.name.isEmpty ? 'arg$count' : field.name; /// Generates the arguments code for [func] -/// Example: (func, getArgumentName, nullTag) -> 'String? foo, int bar' +/// Example: (func, getArgumentName) -> 'String? foo, int bar' String _getMethodArgumentsSignature( Method func, String Function(int index, NamedType arg) getArgumentName, - String nullTag, ) { return func.arguments.isEmpty ? '' : indexMap(func.arguments, (int index, NamedType arg) { - final String type = _addGenericTypesNullable(arg.type, nullTag); + final String type = _addGenericTypesNullable(arg.type); final String argName = getArgumentName(index, arg); return '$type $argName'; }).join(', '); @@ -154,8 +148,6 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) { final String codecName = _getCodecName(api); _writeCodec(indent, codecName, api, root); indent.addln(''); - final String nullTag = opt.isNullSafe ? '?' : ''; - final String unwrapOperator = opt.isNullSafe ? '!' : ''; bool first = true; indent.write('class ${api.name} '); indent.scoped('{', '}', () { @@ -163,9 +155,9 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) { /// Constructor for [${api.name}]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. -${api.name}({BinaryMessenger$nullTag binaryMessenger}) : _binaryMessenger = binaryMessenger; +${api.name}({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; -final BinaryMessenger$nullTag _binaryMessenger; +final BinaryMessenger? _binaryMessenger; '''); indent.writeln('static const MessageCodec codec = $codecName();'); @@ -183,41 +175,39 @@ final BinaryMessenger$nullTag _binaryMessenger; _getSafeArgumentName(index, type); final Iterable argNames = indexMap(func.arguments, argNameFunc); sendArgument = '[${argNames.join(', ')}]'; - argSignature = _getMethodArgumentsSignature(func, argNameFunc, nullTag); + argSignature = _getMethodArgumentsSignature(func, argNameFunc); } indent.write( - 'Future<${_addGenericTypesNullable(func.returnType, nullTag)}> ${func.name}($argSignature) async ', + 'Future<${_addGenericTypesNullable(func.returnType)}> ${func.name}($argSignature) async ', ); indent.scoped('{', '}', () { final String channelName = makeChannelName(api, func); indent.writeln( - 'final BasicMessageChannel channel = BasicMessageChannel('); + 'final BasicMessageChannel channel = BasicMessageChannel('); indent.nest(2, () { indent.writeln( '\'$channelName\', codec, binaryMessenger: _binaryMessenger);', ); }); - final String returnType = - _makeGenericTypeArguments(func.returnType, nullTag); - final String castCall = _makeGenericCastCall(func.returnType, nullTag); + final String returnType = _makeGenericTypeArguments(func.returnType); + final String castCall = _makeGenericCastCall(func.returnType); const String accessor = 'replyMap[\'${Keys.result}\']'; - final String unwrapper = - func.returnType.isNullable ? '' : unwrapOperator; + final String unwrapper = func.returnType.isNullable ? '' : '!'; final String returnStatement = func.returnType.isVoid ? 'return;' - : 'return ($accessor as $returnType$nullTag)$unwrapper$castCall;'; + : 'return ($accessor as $returnType?)$unwrapper$castCall;'; indent.format(''' -final Map$nullTag replyMap =\n\t\tawait channel.send($sendArgument) as Map$nullTag; +final Map? replyMap =\n\t\tawait channel.send($sendArgument) as Map?; if (replyMap == null) { \tthrow PlatformException( \t\tcode: 'channel-error', \t\tmessage: 'Unable to establish connection on channel.', \t); } else if (replyMap['error'] != null) { -\tfinal Map error = (replyMap['${Keys.error}'] as Map$nullTag)$unwrapOperator; +\tfinal Map error = (replyMap['${Keys.error}'] as Map?)!; \tthrow PlatformException( -\t\tcode: (error['${Keys.errorCode}'] as String$nullTag)$unwrapOperator, -\t\tmessage: error['${Keys.errorMessage}'] as String$nullTag, +\t\tcode: (error['${Keys.errorCode}'] as String?)!, +\t\tmessage: error['${Keys.errorMessage}'] as String?, \t\tdetails: error['${Keys.errorDetails}'], \t);'''); // On iOS we can return nil from functions to accommodate error @@ -260,8 +250,6 @@ void _writeFlutterApi( assert(api.location == ApiLocation.flutter); final String codecName = _getCodecName(api); _writeCodec(indent, codecName, api, root); - final String nullTag = opt.isNullSafe ? '?' : ''; - final String unwrapOperator = opt.isNullSafe ? '!' : ''; indent.write('abstract class ${api.name} '); indent.scoped('{', '}', () { indent.writeln('static const MessageCodec codec = $codecName();'); @@ -269,23 +257,22 @@ void _writeFlutterApi( for (final Method func in api.methods) { final bool isAsync = func.isAsynchronous; final String returnType = isAsync - ? 'Future<${_addGenericTypesNullable(func.returnType, nullTag)}>' - : _addGenericTypesNullable(func.returnType, nullTag); + ? 'Future<${_addGenericTypesNullable(func.returnType)}>' + : _addGenericTypesNullable(func.returnType); final String argSignature = _getMethodArgumentsSignature( func, _getArgumentName, - nullTag, ); indent.writeln('$returnType ${func.name}($argSignature);'); } indent.write( - 'static void setup(${api.name}$nullTag api, {BinaryMessenger$nullTag binaryMessenger}) '); + 'static void setup(${api.name}? api, {BinaryMessenger? binaryMessenger}) '); indent.scoped('{', '}', () { for (final Method func in api.methods) { indent.write(''); indent.scoped('{', '}', () { indent.writeln( - 'final BasicMessageChannel channel = BasicMessageChannel(', + 'final BasicMessageChannel channel = BasicMessageChannel(', ); final String channelName = channelNameFunc == null ? makeChannelName(api, func) @@ -304,14 +291,14 @@ void _writeFlutterApi( indent.add(' else '); indent.scoped('{', '}', () { indent.write( - 'channel.$messageHandlerSetter((Object$nullTag message) async ', + 'channel.$messageHandlerSetter((Object? message) async ', ); indent.scoped('{', '});', () { final String returnType = - _addGenericTypesNullable(func.returnType, nullTag); + _addGenericTypesNullable(func.returnType); final bool isAsync = func.isAsynchronous; final String emptyReturnStatement = isMockHandler - ? 'return {};' + ? 'return {};' : func.returnType.isVoid ? 'return;' : 'return null;'; @@ -325,19 +312,18 @@ void _writeFlutterApi( ); const String argsArray = 'args'; indent.writeln( - 'final List $argsArray = (message as List$nullTag)$unwrapOperator;'); + 'final List $argsArray = (message as List?)!;'); String argNameFunc(int index, NamedType type) => _getSafeArgumentName(index, type); enumerate(func.arguments, (int count, NamedType arg) { - final String argType = _addGenericTypes(arg.type, nullTag); + final String argType = _addGenericTypes(arg.type); final String argName = argNameFunc(count, arg); final String genericArgType = - _makeGenericTypeArguments(arg.type, nullTag); - final String castCall = - _makeGenericCastCall(arg.type, nullTag); + _makeGenericTypeArguments(arg.type); + final String castCall = _makeGenericCastCall(arg.type); indent.writeln( - 'final $argType$nullTag $argName = ($argsArray[$count] as $genericArgType$nullTag)${castCall.isEmpty ? '' : '$nullTag$castCall'};'); + 'final $argType? $argName = ($argsArray[$count] as $genericArgType?)${castCall.isEmpty ? '' : '?$castCall'};'); if (!arg.type.isNullable) { indent.writeln( 'assert($argName != null, \'Argument for $channelName was null, expected non-null $argType.\');'); @@ -346,7 +332,7 @@ void _writeFlutterApi( final Iterable argNames = indexMap(func.arguments, (int index, NamedType field) { final String name = _getSafeArgumentName(index, field); - return '$name${field.type.isNullable ? '' : unwrapOperator}'; + return '$name${field.type.isNullable ? '' : '!'}'; }); call = 'api.${func.name}(${argNames.join(', ')})'; } @@ -365,7 +351,7 @@ void _writeFlutterApi( } const String returnExpression = 'output'; final String returnStatement = isMockHandler - ? 'return {\'${Keys.result}\': $returnExpression};' + ? 'return {\'${Keys.result}\': $returnExpression};' : 'return $returnExpression;'; indent.writeln(returnStatement); } @@ -379,42 +365,40 @@ void _writeFlutterApi( /// Converts a [List] of [TypeDeclaration]s to a comma separated [String] to be /// used in Dart code. -String _flattenTypeArguments(List args, String nullTag) { +String _flattenTypeArguments(List args) { return args .map((TypeDeclaration arg) => arg.typeArguments.isEmpty - ? '${arg.baseName}$nullTag' - : '${arg.baseName}<${_flattenTypeArguments(arg.typeArguments, nullTag)}>$nullTag') + ? '${arg.baseName}?' + : '${arg.baseName}<${_flattenTypeArguments(arg.typeArguments)}>?') .join(', '); } /// Creates the type declaration for use in Dart code from a [NamedType] making sure /// that type arguments are used for primitive generic types. -String _addGenericTypes(TypeDeclaration type, String nullTag) { +String _addGenericTypes(TypeDeclaration type) { final List typeArguments = type.typeArguments; switch (type.baseName) { case 'List': return (typeArguments.isEmpty) - ? 'List' - : 'List<${_flattenTypeArguments(typeArguments, nullTag)}>'; + ? 'List' + : 'List<${_flattenTypeArguments(typeArguments)}>'; case 'Map': return (typeArguments.isEmpty) - ? 'Map' - : 'Map<${_flattenTypeArguments(typeArguments, nullTag)}>'; + ? 'Map' + : 'Map<${_flattenTypeArguments(typeArguments)}>'; default: return type.baseName; } } -String _addGenericTypesNullable(TypeDeclaration type, String nullTag) { - final String genericdType = _addGenericTypes(type, nullTag); - return type.isNullable ? '$genericdType$nullTag' : genericdType; +String _addGenericTypesNullable(TypeDeclaration type) { + final String genericdType = _addGenericTypes(type); + return type.isNullable ? '$genericdType?' : genericdType; } /// Generates Dart source code for the given AST represented by [root], /// outputting the code to [sink]. void generateDart(DartOptions opt, Root root, StringSink sink) { - final String nullTag = opt.isNullSafe ? '?' : ''; - final String unwrapOperator = opt.isNullSafe ? '!' : ''; final List customClassNames = root.classes.map((Class x) => x.name).toList(); final List customEnumNames = @@ -430,7 +414,7 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { indent.writeln( '// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name', ); - indent.writeln('// @dart = ${opt.isNullSafe ? '2.12' : '2.8'}'); + indent.writeln('// @dart = 2.12'); } void writeEnums() { @@ -471,17 +455,17 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { indent.write('Object encode() '); indent.scoped('{', '}', () { indent.writeln( - 'final Map pigeonMap = {};', + 'final Map pigeonMap = {};', ); for (final NamedType field in klass.fields) { indent.write('pigeonMap[\'${field.name}\'] = '); if (customClassNames.contains(field.type.baseName)) { indent.addln( - '${field.name} == null ? null : ${field.name}$unwrapOperator.encode();', + '${field.name}?.encode();', ); } else if (customEnumNames.contains(field.type.baseName)) { indent.addln( - '${field.name} == null ? null : ${field.name}$unwrapOperator.index;', + '${field.name}?.index;', ); } else { indent.addln('${field.name};'); @@ -496,32 +480,29 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { if (customClassNames.contains(field.type.baseName)) { indent.format(''' pigeonMap['${field.name}'] != null -\t\t? ${field.type.baseName}.decode(pigeonMap['${field.name}']$unwrapOperator) +\t\t? ${field.type.baseName}.decode(pigeonMap['${field.name}']!) \t\t: null''', leadingSpace: false, trailingNewline: false); } else if (customEnumNames.contains(field.type.baseName)) { indent.format(''' pigeonMap['${field.name}'] != null -\t\t? ${field.type.baseName}.values[pigeonMap['${field.name}']$unwrapOperator as int] +\t\t? ${field.type.baseName}.values[pigeonMap['${field.name}']! as int] \t\t: null''', leadingSpace: false, trailingNewline: false); } else if (field.type.typeArguments.isNotEmpty) { - final String genericType = - _makeGenericTypeArguments(field.type, nullTag); - final String castCall = _makeGenericCastCall(field.type, nullTag); - final String castCallPrefix = - field.type.isNullable ? nullTag : unwrapOperator; + final String genericType = _makeGenericTypeArguments(field.type); + final String castCall = _makeGenericCastCall(field.type); + final String castCallPrefix = field.type.isNullable ? '?' : '!'; indent.add( - '(pigeonMap[\'${field.name}\'] as $genericType$nullTag)$castCallPrefix$castCall', + '(pigeonMap[\'${field.name}\'] as $genericType?)$castCallPrefix$castCall', ); } else { - final String genericdType = - _addGenericTypesNullable(field.type, nullTag); + final String genericdType = _addGenericTypesNullable(field.type); if (field.type.isNullable) { indent.add( 'pigeonMap[\'${field.name}\'] as $genericdType', ); } else { indent.add( - 'pigeonMap[\'${field.name}\']$unwrapOperator as $genericdType', + 'pigeonMap[\'${field.name}\']! as $genericdType', ); } } @@ -532,7 +513,7 @@ pigeonMap['${field.name}'] != null ); indent.scoped('{', '}', () { indent.writeln( - 'final Map pigeonMap = message as Map;', + 'final Map pigeonMap = message as Map;', ); indent.write('return ${klass.name}'); indent.scoped('(', ');', () { @@ -551,7 +532,7 @@ pigeonMap['${field.name}'] != null writeConstructor(); indent.addln(''); for (final NamedType field in klass.fields) { - final String datatype = _addGenericTypesNullable(field.type, nullTag); + final String datatype = _addGenericTypesNullable(field.type); indent.writeln('$datatype ${field.name};'); } if (klass.fields.isNotEmpty) { @@ -602,7 +583,7 @@ void generateTestDart( '// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis', ); indent.writeln('// ignore_for_file: avoid_relative_lib_imports'); - indent.writeln('// @dart = ${opt.isNullSafe ? '2.12' : '2.8'}'); + indent.writeln('// @dart = 2.12'); indent.writeln('import \'dart:async\';'); indent.writeln( 'import \'dart:typed_data\' show Uint8List, Int32List, Int64List, Float64List;', diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index f32f202b30c3..5b9ac85eea50 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -8,7 +8,7 @@ import 'dart:mirrors'; import 'ast.dart'; /// The current version of pigeon. This must match the version in pubspec.yaml. -const String pigeonVersion = '2.0.4'; +const String pigeonVersion = '3.0.0'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index 85144d9c58c7..0b5e75e1c766 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -1041,9 +1041,6 @@ options: ..addOption('java_out', help: 'Path to generated Java file (.java).') ..addOption('java_package', help: 'The package that generated Java code will be in.') - ..addFlag('dart_null_safety', - help: 'Makes generated Dart code have null safety annotations', - defaultsTo: true) ..addOption('objc_header_out', help: 'Path to generated Objective-C header file (.h).') ..addOption('objc_prefix', @@ -1082,9 +1079,6 @@ options: javaOptions: JavaOptions( package: results['java_package'], ), - dartOptions: DartOptions( - isNullSafe: results['dart_null_safety'], - ), copyrightHeader: results['copyright_header'], oneLanguage: results['one_language'], astOut: results['ast_out'], diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 8f78999e7afd..b7911aef95a3 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon 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%3Apigeon -version: 2.0.4 # This must match the version in lib/generator_tools.dart +version: 3.0.0 # This must match the version in lib/generator_tools.dart environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/pigeon/run_tests.sh b/packages/pigeon/run_tests.sh index 5e311ead4e1c..be5cd99d10e3 100755 --- a/packages/pigeon/run_tests.sh +++ b/packages/pigeon/run_tests.sh @@ -86,38 +86,26 @@ test_pigeon_android() { # test_null_safe_dart() # # Compiles the pigeon file to a temp directory and attempts to run the dart -# analyzer on it with and without null safety turned on. +# analyzer on it. test_pigeon_dart() { echo "test_pigeon_dart($1)" - temp_dir_1=$(mktmpdir) - temp_dir_2=$(mktmpdir) - - $run_pigeon \ - --input $1 \ - --dart_out $temp_dir_1/pigeon.dart & - null_safe_gen_pid=$! + temp_dir=$(mktmpdir) $run_pigeon \ - --no-dart_null_safety \ --input $1 \ - --dart_out $temp_dir_2/pigeon.dart & - non_null_safe_gen_pid=$! + --dart_out $temp_dir/pigeon.dart & + gen_pid=$! - wait $null_safe_gen_pid - wait $non_null_safe_gen_pid + wait $gen_pid # `./e2e_tests/test_objc/.packages` is used to get access to Flutter since # Pigeon doesn't depend on Flutter. - dartanalyzer $temp_dir_1/pigeon.dart --fatal-infos --fatal-warnings --packages ./e2e_tests/test_objc/.packages & - null_safe_analyze_pid=$! - dartanalyzer $temp_dir_2/pigeon.dart --fatal-infos --fatal-warnings --packages ./e2e_tests/test_objc/.packages & - non_null_safe_analyze_pid=$! + dart analyze $temp_dir/pigeon.dart --fatal-infos --fatal-warnings --packages ./e2e_tests/test_objc/.packages & + analyze_pid=$! - wait $null_safe_analyze_pid - wait $non_null_safe_analyze_pid + wait $analyze_pid - rm -rf $temp_dir_1 - rm -rf $temp_dir_2 + rm -rf $temp_dir } print_usage() { @@ -184,7 +172,7 @@ get_java_linter_formatter() { } run_dart_unittests() { - dart pub run pigeon:run_tests -t dart_unittests + dart run pigeon:run_tests -t dart_unittests } test_command_line() { @@ -204,11 +192,11 @@ test_command_line() { } run_flutter_unittests() { - dart pub run pigeon:run_tests -t flutter_unittests + dart run pigeon:run_tests -t flutter_unittests } run_mock_handler_tests() { - dart pub run pigeon:run_tests -t mock_handler_tests + dart run pigeon:run_tests -t mock_handler_tests } run_dart_compilation_tests() { diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index 00c815854712..4f03de674657 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -27,10 +27,10 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); - expect(code, contains(' dataType1 field1;')); + expect(code, contains(' dataType1? field1;')); }); test('gen one enum', () { @@ -47,7 +47,7 @@ void main() { enums: [anEnum], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('enum Foobar')); expect(code, contains(' one,')); @@ -94,7 +94,7 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, contains('Future doSomething(Input arg_input)')); @@ -121,7 +121,7 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, contains('Future add(int arg_x, int arg_y)')); @@ -149,7 +149,7 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, contains('int add(int x, int y)')); @@ -188,18 +188,18 @@ void main() { ) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect( code, contains( - 'pigeonMap[\'nested\'] = nested == null ? null : nested.encode()', + 'pigeonMap[\'nested\'] = nested?.encode()', ), ); expect( code.replaceAll('\n', ' ').replaceAll(' ', ''), contains( - 'nested: pigeonMap[\'nested\'] != null ? Input.decode(pigeonMap[\'nested\']) : null', + 'nested: pigeonMap[\'nested\'] != null ? Input.decode(pigeonMap[\'nested\']!) : null', ), ); }); @@ -244,7 +244,7 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('abstract class Api')); expect(code, contains('static void setup(Api')); @@ -281,7 +281,7 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doSomething')); expect(code, contains('return;')); @@ -317,7 +317,7 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); // The next line verifies that we're not setting a variable to the value of "doSomething", but // ignores the line where we assert the value of the argument isn't null, since on that line @@ -349,7 +349,7 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, matches('output.*=.*doSomething[(][)]')); expect(code, contains('Output doSomething();')); @@ -394,59 +394,9 @@ void main() { ) ]); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); - expect(code, - contains('pigeonMap[\'enum1\'] = enum1 == null ? null : enum1.index;')); - expect(code, contains('? Enum.values[pigeonMap[\'enum1\'] as int]')); - expect(code, contains('EnumClass doSomething(EnumClass arg0);')); - }); - - test('flutter enum argument with enum class nullsafe', () { - final Root root = Root(apis: [ - Api(name: 'Api', location: ApiLocation.flutter, methods: [ - Method( - name: 'doSomething', - arguments: [ - NamedType( - type: const TypeDeclaration( - baseName: 'EnumClass', - isNullable: false, - ), - name: '', - offset: null) - ], - returnType: - const TypeDeclaration(baseName: 'EnumClass', isNullable: false), - isAsynchronous: false, - ) - ]) - ], classes: [ - Class(name: 'EnumClass', fields: [ - NamedType( - type: const TypeDeclaration( - baseName: 'Enum', - isNullable: true, - ), - name: 'enum1', - offset: null) - ]), - ], enums: [ - Enum( - name: 'Enum', - members: [ - 'one', - 'two', - ], - ) - ]); - final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); - final String code = sink.toString(); - expect( - code, - contains( - 'pigeonMap[\'enum1\'] = enum1 == null ? null : enum1!.index;')); + expect(code, contains('pigeonMap[\'enum1\'] = enum1?.index;')); expect(code, contains('? Enum.values[pigeonMap[\'enum1\']! as int]')); expect(code, contains('EnumClass doSomething(EnumClass arg0);')); }); @@ -474,7 +424,7 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, matches('channel.send[(]null[)]')); }); @@ -538,7 +488,7 @@ void main() { ], enums: []); final StringBuffer mainCodeSink = StringBuffer(); final StringBuffer testCodeSink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, mainCodeSink); + generateDart(const DartOptions(), root, mainCodeSink); final String mainCode = mainCodeSink.toString(); expect(mainCode, isNot(contains('import \'fo\\\'o.dart\';'))); expect(mainCode, contains('class Api {')); @@ -546,39 +496,14 @@ void main() { expect(mainCode, isNot(contains('.ApiMock.doSomething'))); expect(mainCode, isNot(contains('\'${Keys.result}\': output'))); expect(mainCode, isNot(contains('return {};'))); - generateTestDart( - const DartOptions(isNullSafe: false), root, testCodeSink, "fo'o.dart"); + generateTestDart(const DartOptions(), root, testCodeSink, "fo'o.dart"); final String testCode = testCodeSink.toString(); expect(testCode, contains('import \'fo\\\'o.dart\';')); expect(testCode, isNot(contains('class Api {'))); expect(testCode, contains('abstract class ApiMock')); expect(testCode, isNot(contains('.ApiMock.doSomething'))); expect(testCode, contains('\'${Keys.result}\': output')); - expect(testCode, contains('return {};')); - }); - - test('opt out of nndb', () { - final Class klass = Class( - name: 'Foobar', - fields: [ - NamedType( - type: const TypeDeclaration( - baseName: 'dataType1', - isNullable: true, - ), - name: 'field1', - offset: null), - ], - ); - final Root root = Root( - apis: [], - classes: [klass], - enums: [], - ); - final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); - final String code = sink.toString(); - expect(code, contains('// @dart = 2.8')); + expect(testCode, contains('return {};')); }); test('gen one async Flutter Api', () { @@ -621,12 +546,12 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('abstract class Api')); expect(code, contains('Future doSomething(Input arg0);')); expect( - code, contains('final Output output = await api.doSomething(arg0);')); + code, contains('final Output output = await api.doSomething(arg0!);')); }); test('gen one async Flutter Api with void return', () { @@ -668,7 +593,7 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, isNot(matches('=.s*doSomething'))); expect(code, contains('await api.doSomething(')); @@ -715,7 +640,7 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, matches('Output.*doSomething.*Input')); @@ -744,7 +669,7 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: false), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, matches('channel.send[(]null[)]')); }); @@ -757,8 +682,7 @@ void main() { final Root root = Root(apis: [], classes: [], enums: []); final StringBuffer sink = StringBuffer(); generateDart( - DartOptions( - isNullSafe: false, copyrightHeader: _makeIterable('hello world')), + DartOptions(copyrightHeader: _makeIterable('hello world')), root, sink, ); @@ -787,7 +711,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); expect(code, contains(' List? field1;')); @@ -815,7 +739,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); expect(code, contains(' Map? field1;')); @@ -845,7 +769,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('doit(List arg')); }); @@ -874,7 +798,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('doit(List arg')); }); @@ -898,7 +822,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future> doit(')); expect( @@ -936,7 +860,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('List doit(')); expect( @@ -963,7 +887,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit()')); expect(code, contains('return (replyMap[\'result\'] as int?);')); @@ -987,7 +911,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit()')); expect(code, contains('return (replyMap[\'result\'] as int?);')); @@ -1010,7 +934,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('int? doit();')); expect(code, contains('final int? output = api.doit();')); @@ -1034,7 +958,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit();')); expect(code, contains('final int? output = await api.doit();')); @@ -1057,7 +981,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect( code, @@ -1086,7 +1010,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit(int? arg_foo) async {')); }); @@ -1112,7 +1036,7 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(const DartOptions(isNullSafe: true), root, sink); + generateDart(const DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('void doit(int? foo);')); }); diff --git a/packages/pigeon/test/pigeon_lib_test.dart b/packages/pigeon/test/pigeon_lib_test.dart index 6d6447cdb401..d40c01520bc6 100644 --- a/packages/pigeon/test/pigeon_lib_test.dart +++ b/packages/pigeon/test/pigeon_lib_test.dart @@ -329,12 +329,6 @@ abstract class NestorApi { expect(classNames.contains('OnlyVisibleFromNesting'), true); }); - test('null safety flag', () { - final PigeonOptions results = - Pigeon.parseArgs(['--dart_null_safety']); - expect(results.dartOptions?.isNullSafe, isTrue); - }); - test('copyright flag', () { final PigeonOptions results = Pigeon.parseArgs(['--copyright_header', 'foobar.txt']); @@ -423,7 +417,7 @@ class Bar { @HostApi() abstract class NotificationsHostApi { void doit(Foo foo); -} +} '''; final ParseResults results = _parseSource(code); expect(results.errors.length, 0); @@ -462,7 +456,7 @@ abstract class Api { test('test field initialization', () { const String code = ''' class Foo { - int? x = 123; + int? x = 123; } @HostApi()