diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index e85ec4872608..201508e4dae9 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.0.17 + +* [dart_test] Adds missing linter ignores. +* [objc] Factors out helper function for reading from NSDictionary's. +* [objc] Renames static variables to match Google style. + ## 1.0.16 * Updates behavior of run\_tests.dart with no arguments. diff --git a/packages/pigeon/bin/run_tests.dart b/packages/pigeon/bin/run_tests.dart index 53e82c1396ae..927c5178ca7a 100644 --- a/packages/pigeon/bin/run_tests.dart +++ b/packages/pigeon/bin/run_tests.dart @@ -7,7 +7,7 @@ /// /// usage: pub run pigeon:run_tests //////////////////////////////////////////////////////////////////////////////// -import 'dart:io' show Process, Platform, exit, stdout, stderr; +import 'dart:io' show File, Process, Platform, exit, stderr, stdout; import 'package:args/args.dart'; import 'package:meta/meta.dart'; import 'package:pigeon/functional.dart'; @@ -103,6 +103,34 @@ Future _generateDart(Map jobs) async { return 0; } +Future _analyzeFlutterUnitTests(String flutterUnitTestsPath) async { + final String messagePath = '$flutterUnitTestsPath/lib/message.gen.dart'; + final String messageTestPath = '$flutterUnitTestsPath/test/message_test.dart'; + final int generateTestCode = await _runPigeon( + input: 'pigeons/message.dart', + dartOut: messagePath, + dartTestOut: messageTestPath, + streamOutput: true, + ); + if (generateTestCode != 0) { + return generateTestCode; + } + + final int analyzeCode = await _runProcess( + 'flutter', + ['analyze'], + workingDirectory: flutterUnitTestsPath, + ); + if (analyzeCode != 0) { + return analyzeCode; + } + + // Delete these files that were just generated to help with the analyzer step. + File(messagePath).deleteSync(); + File(messageTestPath).deleteSync(); + return 0; +} + Future _runFlutterUnitTests() async { const String flutterUnitTestsPath = 'platform_tests/flutter_null_safe_unit_tests'; @@ -121,6 +149,11 @@ Future _runFlutterUnitTests() async { return generateCode; } + final int analyzeCode = await _analyzeFlutterUnitTests(flutterUnitTestsPath); + if (analyzeCode != 0) { + return analyzeCode; + } + final int testCode = await _runProcess( 'flutter', ['test'], diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 29893dcf5074..44693ace43f0 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -578,8 +578,9 @@ void generateTestDart( indent.writeln('// $generatedCodeWarning'); indent.writeln('// $seeAlsoWarning'); indent.writeln( - '// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import', + '// 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('import \'dart:async\';'); indent.writeln( @@ -590,6 +591,8 @@ void generateTestDart( indent.writeln('import \'package:flutter/services.dart\';'); indent.writeln('import \'package:flutter_test/flutter_test.dart\';'); indent.writeln(''); + // TODO(gaaclarke): Switch from relative paths to URIs. This fails in new versions of Dart, + // https://github.com/flutter/flutter/issues/97744. indent.writeln( 'import \'${_escapeForDartSingleQuotedString(mainDartFile)}\';', ); diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 1dfbcdf1200d..ae03da6134c9 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 = '1.0.16'; +const String pigeonVersion = '1.0.17'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/lib/objc_generator.dart b/packages/pigeon/lib/objc_generator.dart index e23240729757..8419760efca6 100644 --- a/packages/pigeon/lib/objc_generator.dart +++ b/packages/pigeon/lib/objc_generator.dart @@ -305,13 +305,13 @@ void _writeCodec( @end NSObject *${_getCodecGetterName(options.prefix, api.name)}() { -\tstatic dispatch_once_t s_pred = 0; -\tstatic FlutterStandardMessageCodec *s_sharedObject = nil; -\tdispatch_once(&s_pred, ^{ +\tstatic dispatch_once_t sPred = 0; +\tstatic FlutterStandardMessageCodec *sSharedObject = nil; +\tdispatch_once(&sPred, ^{ \t\t$readerWriterName *readerWriter = [[$readerWriterName alloc] init]; -\t\ts_sharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; +\t\tsSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; \t}); -\treturn s_sharedObject; +\treturn sSharedObject; } '''); } @@ -551,9 +551,9 @@ String _dictGetter( if (prefix != null) { className = '$prefix$className'; } - return '[$className fromMap:$dict[@"${field.name}"]]'; + return '[$className fromMap:GetNullableObject($dict, @"${field.name}")]'; } else { - return '$dict[@"${field.name}"]'; + return 'GetNullableObject($dict, @"${field.name}")'; } } @@ -811,7 +811,7 @@ void generateObjcSource(ObjcOptions options, Root root, StringSink sink) { indent.writeln('#endif'); } - void writeWrapResultFunction() { + void writeHelperFunctions() { indent.format(''' static NSDictionary *wrapResult(id result, FlutterError *error) { \tNSDictionary *errorDict = (NSDictionary *)[NSNull null]; @@ -827,6 +827,12 @@ static NSDictionary *wrapResult(id result, FlutterError *error) \t\t\t@"${Keys.error}": errorDict, \t\t\t}; }'''); + indent.format(''' +static id GetNullableObject(NSDictionary* dict, id key) { +\tid result = dict[key]; +\treturn (result == [NSNull null]) ? nil : result; +} +'''); } void writeDataClassExtension(Class klass) { @@ -864,15 +870,9 @@ static NSDictionary *wrapResult(id result, FlutterError *error) } else { indent.writeln( '$resultName.${field.name} = ${_dictGetter(classNames, 'dict', field, options.prefix)};'); - if (field.type.isNullable) { - indent.write( - 'if ((NSNull *)$resultName.${field.name} == [NSNull null]) '); - indent.scoped('{', '}', () { - indent.writeln('$resultName.${field.name} = nil;'); - }); - } else { - indent.writeln( - 'NSAssert((NSNull *)$resultName.${field.name} != [NSNull null], @"");'); + if (!field.type.isNullable) { + indent + .writeln('NSAssert($resultName.${field.name} != nil, @"");'); } } } @@ -915,7 +915,7 @@ static NSDictionary *wrapResult(id result, FlutterError *error) indent.writeln(''); writeArcEnforcer(); indent.addln(''); - writeWrapResultFunction(); + writeHelperFunctions(); indent.addln(''); root.classes.forEach(writeDataClassExtension); indent.writeln(''); diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index dd31610c82c5..858518c2fe5e 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -350,7 +350,7 @@ class DartTestGenerator implements Generator { @override IOSink? shouldGenerate(PigeonOptions options) { - if (options.dartTestOut != null && options.dartOut != null) { + if (options.dartTestOut != null) { return _openSink(options.dartTestOut); } else { return null; diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 594479f6d751..f6da1f97776c 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: 1.0.16 # This must match the version in lib/generator_tools.dart +version: 1.0.17 # This must match the version in lib/generator_tools.dart environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart index 6ff4ccecae20..f53444166065 100644 --- a/packages/pigeon/test/objc_generator_test.dart +++ b/packages/pigeon/test/objc_generator_test.dart @@ -111,7 +111,9 @@ void main() { expect(code, contains('#import "foo.h"')); expect(code, contains('@implementation Foobar')); expect( - code, contains('pigeonResult.enum1 = [dict[@"enum1"] integerValue];')); + code, + contains( + 'pigeonResult.enum1 = [GetNullableObject(dict, @"enum1") integerValue];')); }); test('gen one class header with enum', () { @@ -308,7 +310,8 @@ void main() { generateObjcSource(const ObjcOptions(header: 'foo.h'), root, sink); final String code = sink.toString(); expect(code, contains('@implementation Foobar')); - expect(code, contains('pigeonResult.aBool = dict[@"aBool"];')); + expect(code, + contains('pigeonResult.aBool = GetNullableObject(dict, @"aBool");')); }); test('nested class header', () { @@ -351,8 +354,10 @@ void main() { final StringBuffer sink = StringBuffer(); generateObjcSource(const ObjcOptions(header: 'foo.h'), root, sink); final String code = sink.toString(); - expect(code, - contains('pigeonResult.nested = [Input fromMap:dict[@"nested"]];')); + expect( + code, + contains( + 'pigeonResult.nested = [Input fromMap:GetNullableObject(dict, @"nested")];')); expect(code, matches('[self.nested toMap].*@"nested"')); });