From c9cb43ce1aaaaf94e9998d1ba5b0a7c911f96733 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 14 Dec 2020 11:20:45 -0800 Subject: [PATCH] Migrate the first batch of API samples to null safety (#72169) --- dev/bots/analyze-sample-code.dart | 64 +++++++++---------- .../flutter/lib/src/animation/animation.dart | 3 +- .../src/animation/animation_controller.dart | 9 ++- .../flutter/lib/src/animation/animations.dart | 3 +- packages/flutter/lib/src/animation/tween.dart | 6 +- .../lib/src/animation/tween_sequence.dart | 3 +- .../lib/src/foundation/annotations.dart | 1 - .../lib/src/foundation/assertions.dart | 9 ++- .../lib/src/foundation/diagnostics.dart | 15 ++--- .../flutter/lib/src/painting/borders.dart | 1 - .../flutter/lib/src/painting/box_border.dart | 4 +- .../lib/src/painting/image_provider.dart | 22 +++---- .../flutter/lib/src/semantics/semantics.dart | 1 - 13 files changed, 62 insertions(+), 79 deletions(-) diff --git a/dev/bots/analyze-sample-code.dart b/dev/bots/analyze-sample-code.dart index 40d3b3f0337..b783b0f3afa 100644 --- a/dev/bots/analyze-sample-code.dart +++ b/dev/bots/analyze-sample-code.dart @@ -8,7 +8,6 @@ // bin/cache/dart-sdk/bin/dart dev/bots/analyze-sample-code.dart import 'dart:io'; -import 'dart:isolate'; import 'package:args/args.dart'; import 'package:path/path.dart' as path; @@ -203,6 +202,8 @@ class SampleChecker { return _headers ??= [ '// generated code', '// ignore_for_file: unused_import', + '// ignore_for_file: unused_element', + '// ignore_for_file: unused_local_variable', "import 'dart:async';", "import 'dart:convert';", "import 'dart:math' as math;", @@ -547,8 +548,9 @@ linter: } /// Invokes the analyzer on the given [directory] and returns the stdout. - List _runAnalyzer(Directory directory) { - print('Starting analysis of code samples.'); + List _runAnalyzer(Directory directory, {bool silent}) { + if (!silent) + print('Starting analysis of code samples.'); _createConfigurationFiles(directory); final ProcessResult result = Process.runSync( _flutter, @@ -570,7 +572,7 @@ linter: stderr.removeLast(); } } - if (stderr.isNotEmpty) { + if (stderr.isNotEmpty && stderr.any((String line) => line.isNotEmpty)) { throw 'Cannot analyze dartdocs; unexpected error output:\n$stderr'; } if (stdout.isNotEmpty && stdout.first == 'Building flutter tool...') { @@ -588,9 +590,10 @@ linter: Map> _analyze( Directory directory, Map sections, - Map samples, - ) { - final List errors = _runAnalyzer(directory); + Map samples, { + bool silent = false, + }) { + final List errors = _runAnalyzer(directory, silent: silent); final Map> analysisErrors = >{}; void addAnalysisError(File file, AnalysisError error) { if (analysisErrors.containsKey(file.path)) { @@ -621,10 +624,6 @@ linter: final String errorCode = parts[6]; final int lineNumber = int.parse(line, radix: 10) - (isSnippet ? headerLength : 0); final int columnNumber = int.parse(column, radix: 10); - if (lineNumber < 0 && errorCode == 'unused_import') { - // We don't care about unused imports. - continue; - } // For when errors occur outside of the things we're trying to analyze. if (!isSnippet && !isSample) { @@ -649,10 +648,6 @@ linter: ); } - if (errorCode == 'unused_element' || errorCode == 'unused_local_variable') { - // We don't really care if sample code isn't used! - continue; - } if (isSample) { addAnalysisError( file, @@ -739,7 +734,8 @@ linter: _exitCode = 0; } if (_exitCode == 0) { - print('No analysis errors in samples!'); + if (!silent) + print('No analysis errors in samples!'); assert(analysisErrors.isEmpty); } return analysisErrors; @@ -960,24 +956,28 @@ Future _runInteractive(Directory tempDir, Directory flutterPackage, String print('Using temp dir ${tempDir.path}'); } + void analyze(SampleChecker checker, File file) { + final Map sections = {}; + final Map snippets = {}; + checker._extractSamples([file], silent: true, sectionMap: sections, sampleMap: snippets); + final Map> errors = checker._analyze(checker._tempDirectory, sections, snippets, silent: true); + stderr.writeln('\u001B[2J\u001B[H'); // Clears the old results from the terminal. + if (errors.isNotEmpty) { + for (final String filePath in errors.keys) { + errors[filePath].forEach(stderr.writeln); + } + stderr.writeln('\nFound ${errors.length} errors.'); + } else { + stderr.writeln('\nNo issues found.'); + } + } + final SampleChecker checker = SampleChecker(flutterPackage, tempDirectory: tempDir) - .._createConfigurationFiles(tempDir) - .._extractSamples([file], silent: true); + .._createConfigurationFiles(tempDir); + analyze(checker, file); - await Isolate.spawn(_watcher, [checker, file]); - - await Process.start( - _flutter, - ['--no-wrap', 'analyze', '--no-preamble', '--no-congratulate', '--watch', '.'], - workingDirectory: tempDir.absolute.path, - mode: ProcessStartMode.inheritStdio - ); -} - -void _watcher(List args) { - final File file = args.last as File; - final SampleChecker checker = args.first as SampleChecker; Watcher(file.absolute.path).events.listen((_) { - checker._extractSamples([file], silent: true); + print('\n\nRerunning...'); + analyze(checker, file); }); } diff --git a/packages/flutter/lib/src/animation/animation.dart b/packages/flutter/lib/src/animation/animation.dart index 74a6fb36575..edfeef12405 100644 --- a/packages/flutter/lib/src/animation/animation.dart +++ b/packages/flutter/lib/src/animation/animation.dart @@ -8,8 +8,7 @@ import 'package:flutter/foundation.dart'; import 'tween.dart'; // Examples can assume: -// // @dart = 2.9 -// AnimationController _controller; +// late AnimationController _controller; /// The status of an animation. enum AnimationStatus { diff --git a/packages/flutter/lib/src/animation/animation_controller.dart b/packages/flutter/lib/src/animation/animation_controller.dart index f3da2671194..95f2f75deaa 100644 --- a/packages/flutter/lib/src/animation/animation_controller.dart +++ b/packages/flutter/lib/src/animation/animation_controller.dart @@ -17,9 +17,8 @@ import 'listener_helpers.dart'; export 'package:flutter/scheduler.dart' show TickerFuture, TickerCanceled; // Examples can assume: -// // @dart = 2.9 -// AnimationController _controller, fadeAnimationController, sizeAnimationController; -// bool dismissed; +// late AnimationController _controller, fadeAnimationController, sizeAnimationController; +// late bool dismissed; // void setState(VoidCallback fn) { } /// The direction in which an animation is running. @@ -137,7 +136,7 @@ enum AnimationBehavior { /// /// ```dart /// class Foo extends StatefulWidget { -/// Foo({ Key key, this.duration }) : super(key: key); +/// Foo({ Key? key, required this.duration }) : super(key: key); /// /// final Duration duration; /// @@ -146,7 +145,7 @@ enum AnimationBehavior { /// } /// /// class _FooState extends State with SingleTickerProviderStateMixin { -/// AnimationController _controller; +/// late AnimationController _controller; /// /// @override /// void initState() { diff --git a/packages/flutter/lib/src/animation/animations.dart b/packages/flutter/lib/src/animation/animations.dart index d64ebe192b6..def82f13bf4 100644 --- a/packages/flutter/lib/src/animation/animations.dart +++ b/packages/flutter/lib/src/animation/animations.dart @@ -12,8 +12,7 @@ import 'curves.dart'; import 'listener_helpers.dart'; // Examples can assume: -// // @dart = 2.9 -// AnimationController controller; +// late AnimationController controller; class _AlwaysCompleteAnimation extends Animation { const _AlwaysCompleteAnimation(); diff --git a/packages/flutter/lib/src/animation/tween.dart b/packages/flutter/lib/src/animation/tween.dart index 98178761fb8..773043039b7 100644 --- a/packages/flutter/lib/src/animation/tween.dart +++ b/packages/flutter/lib/src/animation/tween.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import 'dart:ui' show Color, Size, Rect; import 'package:flutter/foundation.dart'; @@ -12,9 +11,8 @@ import 'animations.dart'; import 'curves.dart'; // Examples can assume: -// // @dart = 2.9 -// Animation _animation; -// AnimationController _controller; +// late Animation _animation; +// late AnimationController _controller; /// An object that can produce a value of type `T` given an [Animation] /// as input. diff --git a/packages/flutter/lib/src/animation/tween_sequence.dart b/packages/flutter/lib/src/animation/tween_sequence.dart index 734ec16a1f7..6a6095aa104 100644 --- a/packages/flutter/lib/src/animation/tween_sequence.dart +++ b/packages/flutter/lib/src/animation/tween_sequence.dart @@ -7,8 +7,7 @@ import 'animation.dart'; import 'tween.dart'; // Examples can assume: -// // @dart = 2.9 -// AnimationController myAnimationController; +// late AnimationController myAnimationController; /// Enables creating an [Animation] whose value is defined by a sequence of /// [Tween]s. diff --git a/packages/flutter/lib/src/foundation/annotations.dart b/packages/flutter/lib/src/foundation/annotations.dart index 87cc4c3f859..b57bfac68e6 100644 --- a/packages/flutter/lib/src/foundation/annotations.dart +++ b/packages/flutter/lib/src/foundation/annotations.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. // Examples can assume: -// // @dart = 2.9 // class Cat { } /// A category with which to annotate a class, for documentation diff --git a/packages/flutter/lib/src/foundation/assertions.dart b/packages/flutter/lib/src/foundation/assertions.dart index 9f8ac8a39f4..1f7749017f7 100644 --- a/packages/flutter/lib/src/foundation/assertions.dart +++ b/packages/flutter/lib/src/foundation/assertions.dart @@ -11,11 +11,10 @@ import 'print.dart'; import 'stack_frame.dart'; // Examples can assume: -// // @dart = 2.9 -// String runtimeType; -// bool draconisAlive; -// bool draconisAmulet; -// Diagnosticable draconis; +// late String runtimeType; +// late bool draconisAlive; +// late bool draconisAmulet; +// late Diagnosticable draconis; /// Signature for [FlutterError.onError] handler. typedef FlutterExceptionHandler = void Function(FlutterErrorDetails details); diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index 02a5b819d72..209eaa3360d 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -12,10 +12,9 @@ import 'debug.dart'; import 'object.dart'; // Examples can assume: -// // @dart = 2.9 -// int rows, columns; -// String _name; -// bool inherit; +// late int rows, columns; +// late String _name; +// late bool inherit; /// The various priority levels used to filter which diagnostics are shown and /// omitted. @@ -3069,7 +3068,7 @@ class DiagnosticPropertiesBuilder { } // Examples can assume: -// class ExampleSuperclass with Diagnosticable { String message; double stepWidth; double scale; double paintExtent; double hitTestExtent; double paintExtend; double maxWidth; bool primary; double progress; int maxLines; Duration duration; int depth; dynamic boxShadow; dynamic style; bool hasSize; Matrix4 transform; Map handles; Color color; bool obscureText; ImageRepeat repeat; Size size; Widget widget; bool isCurrent; bool keepAlive; TextAlign textAlign; } +// class ExampleSuperclass with Diagnosticable { late String message; late double stepWidth; late double scale; late double paintExtent; late double hitTestExtent; late double paintExtend; late double maxWidth; late bool primary; late double progress; late int maxLines; late Duration duration; late int depth; late dynamic boxShadow; late dynamic style; late bool hasSize; late Matrix4 transform; Map? handles; late Color color; late bool obscureText; late ImageRepeat repeat; late Size size; late Widget widget; late bool isCurrent; late bool keepAlive; late TextAlign textAlign; } /// A mixin class for providing string and [DiagnosticsNode] debug /// representations describing the properties of an object. @@ -3326,9 +3325,9 @@ mixin Diagnosticable { /// properties.add(DiagnosticsProperty>( /// 'handles', /// handles, - /// description: handles != null ? - /// '${handles.length} active client${ handles.length == 1 ? "" : "s" }' : - /// null, + /// description: handles != null + /// ? '${handles!.length} active client${ handles!.length == 1 ? "" : "s" }' + /// : null, /// ifNull: 'no notifications ever received', /// showName: false, /// )); diff --git a/packages/flutter/lib/src/painting/borders.dart b/packages/flutter/lib/src/painting/borders.dart index 66dd879a873..fdc6321351b 100644 --- a/packages/flutter/lib/src/painting/borders.dart +++ b/packages/flutter/lib/src/painting/borders.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import 'dart:math' as math; import 'dart:ui' as ui show lerpDouble; diff --git a/packages/flutter/lib/src/painting/box_border.dart b/packages/flutter/lib/src/painting/box_border.dart index acc3b31fe16..cf7012abd3c 100644 --- a/packages/flutter/lib/src/painting/box_border.dart +++ b/packages/flutter/lib/src/painting/box_border.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import 'package:flutter/foundation.dart'; import 'basic_types.dart'; @@ -11,8 +10,7 @@ import 'borders.dart'; import 'edge_insets.dart'; // Examples can assume: -// // @dart = 2.9 -// BuildContext context; +// late BuildContext context; /// The shape to use when rendering a [Border] or [BoxDecoration]. /// diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index a5d678fbf66..8ec67895a44 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -17,9 +17,6 @@ import 'binding.dart'; import 'image_cache.dart'; import 'image_stream.dart'; -// Examples can assume: -// // @dart = 2.9 - /// Signature for the callback taken by [_createErrorHandlerAndKey]. typedef _KeyAndErrorHandlerCallback = void Function(T key, ImageErrorListener handleError); @@ -239,10 +236,9 @@ typedef DecoderCallback = Future Function(Uint8List bytes, {int? cache /// ```dart /// class MyImage extends StatefulWidget { /// const MyImage({ -/// Key key, -/// @required this.imageProvider, -/// }) : assert(imageProvider != null), -/// super(key: key); +/// Key? key, +/// required this.imageProvider, +/// }) : super(key: key); /// /// final ImageProvider imageProvider; /// @@ -251,8 +247,8 @@ typedef DecoderCallback = Future Function(Uint8List bytes, {int? cache /// } /// /// class _MyImageState extends State { -/// ImageStream _imageStream; -/// ImageInfo _imageInfo; +/// ImageStream? _imageStream; +/// ImageInfo? _imageInfo; /// /// @override /// void didChangeDependencies() { @@ -271,15 +267,15 @@ typedef DecoderCallback = Future Function(Uint8List bytes, {int? cache /// } /// /// void _getImage() { -/// final ImageStream oldImageStream = _imageStream; +/// final ImageStream? oldImageStream = _imageStream; /// _imageStream = widget.imageProvider.resolve(createLocalImageConfiguration(context)); -/// if (_imageStream.key != oldImageStream?.key) { +/// if (_imageStream!.key != oldImageStream?.key) { /// // If the keys are the same, then we got the same image back, and so we don't /// // need to update the listeners. If the key changed, though, we must make sure /// // to switch our listeners to the new image stream. /// final ImageStreamListener listener = ImageStreamListener(_updateImage); /// oldImageStream?.removeListener(listener); -/// _imageStream.addListener(listener); +/// _imageStream!.addListener(listener); /// } /// } /// @@ -293,7 +289,7 @@ typedef DecoderCallback = Future Function(Uint8List bytes, {int? cache /// /// @override /// void dispose() { -/// _imageStream.removeListener(ImageStreamListener(_updateImage)); +/// _imageStream?.removeListener(ImageStreamListener(_updateImage)); /// _imageInfo?.dispose(); /// _imageInfo = null; /// super.dispose(); diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index f5fd3abbefa..1bf93a8014d 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui;