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()