Fix newly enforced package:pedantic lints (dart-lang/watcher#78)

- always_declare_return_types
- annotate_overrides
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_final_fields
- prefer_if_null_operators
- prefer_single_quotes
- use_function_type_syntax_for_parameters

Bump min SDK to 2.2.0 to allow Set literals.
diff --git a/pkgs/watcher/.travis.yml b/pkgs/watcher/.travis.yml
index c15590b..9871d25 100644
--- a/pkgs/watcher/.travis.yml
+++ b/pkgs/watcher/.travis.yml
@@ -2,7 +2,7 @@
 
 dart:
 - dev
-- 2.0.0
+- 2.2.0
 
 dart_task:
 - test
diff --git a/pkgs/watcher/benchmark/path_set.dart b/pkgs/watcher/benchmark/path_set.dart
index 1ec3336..858df3c 100644
--- a/pkgs/watcher/benchmark/path_set.dart
+++ b/pkgs/watcher/benchmark/path_set.dart
@@ -13,11 +13,11 @@
 
 import 'package:watcher/src/path_set.dart';
 
-final String root = Platform.isWindows ? r"C:\root" : "/root";
+final String root = Platform.isWindows ? r'C:\root' : '/root';
 
 /// Base class for benchmarks on [PathSet].
 abstract class PathSetBenchmark extends BenchmarkBase {
-  PathSetBenchmark(String method) : super("PathSet.$method");
+  PathSetBenchmark(String method) : super('PathSet.$method');
 
   final PathSet pathSet = PathSet(root);
 
@@ -30,14 +30,14 @@
   ///
   /// Each virtual directory contains ten entries: either subdirectories or
   /// files.
-  void walkTree(int depth, callback(String path)) {
-    recurse(String path, remainingDepth) {
+  void walkTree(int depth, void Function(String) callback) {
+    void recurse(String path, remainingDepth) {
       for (var i = 0; i < 10; i++) {
         var padded = i.toString().padLeft(2, '0');
         if (remainingDepth == 0) {
-          callback(p.join(path, "file_$padded.txt"));
+          callback(p.join(path, 'file_$padded.txt'));
         } else {
-          var subdir = p.join(path, "subdirectory_$padded");
+          var subdir = p.join(path, 'subdirectory_$padded');
           recurse(subdir, remainingDepth - 1);
         }
       }
@@ -48,16 +48,18 @@
 }
 
 class AddBenchmark extends PathSetBenchmark {
-  AddBenchmark() : super("add()");
+  AddBenchmark() : super('add()');
 
   final List<String> paths = [];
 
+  @override
   void setup() {
     // Make a bunch of paths in about the same order we expect to get them from
     // Directory.list().
     walkTree(3, paths.add);
   }
 
+  @override
   void run() {
     for (var path in paths) {
       pathSet.add(path);
@@ -66,10 +68,11 @@
 }
 
 class ContainsBenchmark extends PathSetBenchmark {
-  ContainsBenchmark() : super("contains()");
+  ContainsBenchmark() : super('contains()');
 
   final List<String> paths = [];
 
+  @override
   void setup() {
     // Add a bunch of paths to the set.
     walkTree(3, (path) {
@@ -80,48 +83,52 @@
     // Add some non-existent paths to test the false case.
     for (var i = 0; i < 100; i++) {
       paths.addAll([
-        "/nope",
-        "/root/nope",
-        "/root/subdirectory_04/nope",
-        "/root/subdirectory_04/subdirectory_04/nope",
-        "/root/subdirectory_04/subdirectory_04/subdirectory_04/nope",
-        "/root/subdirectory_04/subdirectory_04/subdirectory_04/nope/file_04.txt",
+        '/nope',
+        '/root/nope',
+        '/root/subdirectory_04/nope',
+        '/root/subdirectory_04/subdirectory_04/nope',
+        '/root/subdirectory_04/subdirectory_04/subdirectory_04/nope',
+        '/root/subdirectory_04/subdirectory_04/subdirectory_04/nope/file_04.txt',
       ]);
     }
   }
 
+  @override
   void run() {
     var contained = 0;
     for (var path in paths) {
       if (pathSet.contains(path)) contained++;
     }
 
-    if (contained != 10000) throw "Wrong result: $contained";
+    if (contained != 10000) throw 'Wrong result: $contained';
   }
 }
 
 class PathsBenchmark extends PathSetBenchmark {
-  PathsBenchmark() : super("toSet()");
+  PathsBenchmark() : super('toSet()');
 
+  @override
   void setup() {
     walkTree(3, pathSet.add);
   }
 
+  @override
   void run() {
     var count = 0;
     for (var _ in pathSet.paths) {
       count++;
     }
 
-    if (count != 10000) throw "Wrong result: $count";
+    if (count != 10000) throw 'Wrong result: $count';
   }
 }
 
 class RemoveBenchmark extends PathSetBenchmark {
-  RemoveBenchmark() : super("remove()");
+  RemoveBenchmark() : super('remove()');
 
   final List<String> paths = [];
 
+  @override
   void setup() {
     // Make a bunch of paths. Do this here so that we don't spend benchmarked
     // time synthesizing paths.
@@ -136,6 +143,7 @@
     paths.shuffle(random);
   }
 
+  @override
   void run() {
     for (var path in paths) {
       pathSet.remove(path);
@@ -143,7 +151,7 @@
   }
 }
 
-main() {
+void main() {
   AddBenchmark().report();
   ContainsBenchmark().report();
   PathsBenchmark().report();
diff --git a/pkgs/watcher/example/watch.dart b/pkgs/watcher/example/watch.dart
index 1477e42..650a4b8 100644
--- a/pkgs/watcher/example/watch.dart
+++ b/pkgs/watcher/example/watch.dart
@@ -8,9 +8,9 @@
 import 'package:path/path.dart' as p;
 import 'package:watcher/watcher.dart';
 
-main(List<String> arguments) {
+void main(List<String> arguments) {
   if (arguments.length != 1) {
-    print("Usage: watch <directory path>");
+    print('Usage: watch <directory path>');
     return;
   }
 
diff --git a/pkgs/watcher/lib/src/constructable_file_system_event.dart b/pkgs/watcher/lib/src/constructable_file_system_event.dart
index 29b7c8d..0011a8d 100644
--- a/pkgs/watcher/lib/src/constructable_file_system_event.dart
+++ b/pkgs/watcher/lib/src/constructable_file_system_event.dart
@@ -5,8 +5,11 @@
 import 'dart:io';
 
 abstract class _ConstructableFileSystemEvent implements FileSystemEvent {
+  @override
   final bool isDirectory;
+  @override
   final String path;
+  @override
   int get type;
 
   _ConstructableFileSystemEvent(this.path, this.isDirectory);
@@ -14,45 +17,55 @@
 
 class ConstructableFileSystemCreateEvent extends _ConstructableFileSystemEvent
     implements FileSystemCreateEvent {
+  @override
   final type = FileSystemEvent.create;
 
   ConstructableFileSystemCreateEvent(String path, bool isDirectory)
       : super(path, isDirectory);
 
+  @override
   String toString() => "FileSystemCreateEvent('$path')";
 }
 
 class ConstructableFileSystemDeleteEvent extends _ConstructableFileSystemEvent
     implements FileSystemDeleteEvent {
+  @override
   final type = FileSystemEvent.delete;
 
   ConstructableFileSystemDeleteEvent(String path, bool isDirectory)
       : super(path, isDirectory);
 
+  @override
   String toString() => "FileSystemDeleteEvent('$path')";
 }
 
 class ConstructableFileSystemModifyEvent extends _ConstructableFileSystemEvent
     implements FileSystemModifyEvent {
+  @override
   final bool contentChanged;
+  @override
   final type = FileSystemEvent.modify;
 
   ConstructableFileSystemModifyEvent(
       String path, bool isDirectory, this.contentChanged)
       : super(path, isDirectory);
 
+  @override
   String toString() =>
       "FileSystemModifyEvent('$path', contentChanged=$contentChanged)";
 }
 
 class ConstructableFileSystemMoveEvent extends _ConstructableFileSystemEvent
     implements FileSystemMoveEvent {
+  @override
   final String destination;
+  @override
   final type = FileSystemEvent.move;
 
   ConstructableFileSystemMoveEvent(
       String path, bool isDirectory, this.destination)
       : super(path, isDirectory);
 
+  @override
   String toString() => "FileSystemMoveEvent('$path', '$destination')";
 }
diff --git a/pkgs/watcher/lib/src/directory_watcher.dart b/pkgs/watcher/lib/src/directory_watcher.dart
index 8c52ed9..e0ef3fc 100644
--- a/pkgs/watcher/lib/src/directory_watcher.dart
+++ b/pkgs/watcher/lib/src/directory_watcher.dart
@@ -14,7 +14,7 @@
 /// in the directory has changed.
 abstract class DirectoryWatcher implements Watcher {
   /// The directory whose contents are being monitored.
-  @Deprecated("Expires in 1.0.0. Use DirectoryWatcher.path instead.")
+  @Deprecated('Expires in 1.0.0. Use DirectoryWatcher.path instead.')
   String get directory;
 
   /// Creates a new [DirectoryWatcher] monitoring [directory].
diff --git a/pkgs/watcher/lib/src/directory_watcher/linux.dart b/pkgs/watcher/lib/src/directory_watcher/linux.dart
index f3866c6..0a66a12 100644
--- a/pkgs/watcher/lib/src/directory_watcher/linux.dart
+++ b/pkgs/watcher/lib/src/directory_watcher/linux.dart
@@ -25,6 +25,7 @@
 /// (issue 14424).
 class LinuxDirectoryWatcher extends ResubscribableWatcher
     implements DirectoryWatcher {
+  @override
   String get directory => path;
 
   LinuxDirectoryWatcher(String directory)
@@ -33,20 +34,25 @@
 
 class _LinuxDirectoryWatcher
     implements DirectoryWatcher, ManuallyClosedWatcher {
+  @override
   String get directory => _files.root;
+  @override
   String get path => _files.root;
 
+  @override
   Stream<WatchEvent> get events => _eventsController.stream;
   final _eventsController = StreamController<WatchEvent>.broadcast();
 
+  @override
   bool get isReady => _readyCompleter.isCompleted;
 
+  @override
   Future get ready => _readyCompleter.future;
   final _readyCompleter = Completer();
 
   /// A stream group for the [Directory.watch] events of [path] and all its
   /// subdirectories.
-  var _nativeEvents = StreamGroup<FileSystemEvent>();
+  final _nativeEvents = StreamGroup<FileSystemEvent>();
 
   /// All known files recursively within [path].
   final PathSet _files;
@@ -60,7 +66,7 @@
   ///
   /// These are gathered together so that they may all be canceled when the
   /// watcher is closed.
-  final _subscriptions = Set<StreamSubscription>();
+  final _subscriptions = <StreamSubscription>{};
 
   _LinuxDirectoryWatcher(String path) : _files = PathSet(path) {
     _nativeEvents.add(Directory(path)
@@ -93,6 +99,7 @@
     }, cancelOnError: true);
   }
 
+  @override
   void close() {
     for (var subscription in _subscriptions) {
       subscription.cancel();
@@ -128,9 +135,9 @@
 
   /// The callback that's run when a batch of changes comes in.
   void _onBatch(List<FileSystemEvent> batch) {
-    var files = Set<String>();
-    var dirs = Set<String>();
-    var changed = Set<String>();
+    var files = <String>{};
+    var dirs = <String>{};
+    var changed = <String>{};
 
     // inotify event batches are ordered by occurrence, so we treat them as a
     // log of what happened to a file. We only emit events based on the
@@ -250,8 +257,8 @@
 
   /// Like [Stream.listen], but automatically adds the subscription to
   /// [_subscriptions] so that it can be canceled when [close] is called.
-  void _listen<T>(Stream<T> stream, void onData(T event),
-      {Function onError, void onDone(), bool cancelOnError}) {
+  void _listen<T>(Stream<T> stream, void Function(T) onData,
+      {Function onError, void Function() onDone, bool cancelOnError}) {
     StreamSubscription subscription;
     subscription = stream.listen(onData, onError: onError, onDone: () {
       _subscriptions.remove(subscription);
diff --git a/pkgs/watcher/lib/src/directory_watcher/mac_os.dart b/pkgs/watcher/lib/src/directory_watcher/mac_os.dart
index f593fbd..73703cb 100644
--- a/pkgs/watcher/lib/src/directory_watcher/mac_os.dart
+++ b/pkgs/watcher/lib/src/directory_watcher/mac_os.dart
@@ -24,6 +24,7 @@
 /// [Directory.watch].
 class MacOSDirectoryWatcher extends ResubscribableWatcher
     implements DirectoryWatcher {
+  @override
   String get directory => path;
 
   MacOSDirectoryWatcher(String directory)
@@ -32,14 +33,19 @@
 
 class _MacOSDirectoryWatcher
     implements DirectoryWatcher, ManuallyClosedWatcher {
+  @override
   String get directory => path;
+  @override
   final String path;
 
+  @override
   Stream<WatchEvent> get events => _eventsController.stream;
   final _eventsController = StreamController<WatchEvent>.broadcast();
 
+  @override
   bool get isReady => _readyCompleter.isCompleted;
 
+  @override
   Future get ready => _readyCompleter.future;
   final _readyCompleter = Completer();
 
@@ -64,7 +70,7 @@
 
   /// The subscriptions to [Directory.list] calls for listing the contents of a
   /// subdirectory that was moved into the watched directory.
-  final _listSubscriptions = Set<StreamSubscription<FileSystemEntity>>();
+  final _listSubscriptions = <StreamSubscription<FileSystemEntity>>{};
 
   /// The timer for tracking how long we wait for an initial batch of bogus
   /// events (see issue 14373).
@@ -85,6 +91,7 @@
         .then((_) => _readyCompleter.complete());
   }
 
+  @override
   void close() {
     if (_watchSubscription != null) _watchSubscription.cancel();
     if (_initialListSubscription != null) _initialListSubscription.cancel();
@@ -181,19 +188,19 @@
     // directory's full contents will be examined anyway, so we ignore such
     // events. Emitting them could cause useless or out-of-order events.
     var directories = unionAll(batch.map((event) {
-      if (!event.isDirectory) return Set<String>();
+      if (!event.isDirectory) return <String>{};
       if (event is FileSystemMoveEvent) {
-        return Set<String>.from([event.path, event.destination]);
+        return {event.path, event.destination};
       }
-      return Set<String>.from([event.path]);
+      return {event.path};
     }));
 
-    isInModifiedDirectory(String path) =>
+    bool isInModifiedDirectory(String path) =>
         directories.any((dir) => path != dir && path.startsWith(dir));
 
-    addEvent(String path, FileSystemEvent event) {
+    void addEvent(String path, FileSystemEvent event) {
       if (isInModifiedDirectory(path)) return;
-      eventsForPaths.putIfAbsent(path, () => Set<FileSystemEvent>()).add(event);
+      eventsForPaths.putIfAbsent(path, () => <FileSystemEvent>{}).add(event);
     }
 
     for (var event in batch) {
diff --git a/pkgs/watcher/lib/src/directory_watcher/polling.dart b/pkgs/watcher/lib/src/directory_watcher/polling.dart
index f21a239..388f28a 100644
--- a/pkgs/watcher/lib/src/directory_watcher/polling.dart
+++ b/pkgs/watcher/lib/src/directory_watcher/polling.dart
@@ -15,6 +15,7 @@
 /// Periodically polls a directory for changes.
 class PollingDirectoryWatcher extends ResubscribableWatcher
     implements DirectoryWatcher {
+  @override
   String get directory => path;
 
   /// Creates a new polling watcher monitoring [directory].
@@ -25,21 +26,26 @@
   /// and higher CPU usage. Defaults to one second.
   PollingDirectoryWatcher(String directory, {Duration pollingDelay})
       : super(directory, () {
-          return _PollingDirectoryWatcher(directory,
-              pollingDelay != null ? pollingDelay : Duration(seconds: 1));
+          return _PollingDirectoryWatcher(
+              directory, pollingDelay ?? Duration(seconds: 1));
         });
 }
 
 class _PollingDirectoryWatcher
     implements DirectoryWatcher, ManuallyClosedWatcher {
+  @override
   String get directory => path;
+  @override
   final String path;
 
+  @override
   Stream<WatchEvent> get events => _events.stream;
   final _events = StreamController<WatchEvent>.broadcast();
 
+  @override
   bool get isReady => _ready.isCompleted;
 
+  @override
   Future<void> get ready => _ready.future;
   final _ready = Completer<void>();
 
@@ -50,7 +56,7 @@
   /// The previous modification times of the files in the directory.
   ///
   /// Used to tell which files have been modified.
-  final _lastModifieds = Map<String, DateTime>();
+  final _lastModifieds = <String, DateTime>{};
 
   /// The subscription used while [directory] is being listed.
   ///
@@ -70,7 +76,7 @@
   ///
   /// Used to tell which files have been removed: files that are in
   /// [_lastModifieds] but not in here when a poll completes have been removed.
-  final _polledFiles = Set<String>();
+  final _polledFiles = <String>{};
 
   _PollingDirectoryWatcher(this.path, this._pollingDelay) {
     _filesToProcess =
@@ -81,6 +87,7 @@
     _poll();
   }
 
+  @override
   void close() {
     _events.close();
 
@@ -99,7 +106,7 @@
     _filesToProcess.clear();
     _polledFiles.clear();
 
-    endListing() {
+    void endListing() {
       assert(!_events.isClosed);
       _listSubscription = null;
 
diff --git a/pkgs/watcher/lib/src/directory_watcher/windows.dart b/pkgs/watcher/lib/src/directory_watcher/windows.dart
index 8bf6642..2a70edc 100644
--- a/pkgs/watcher/lib/src/directory_watcher/windows.dart
+++ b/pkgs/watcher/lib/src/directory_watcher/windows.dart
@@ -18,6 +18,7 @@
 
 class WindowsDirectoryWatcher extends ResubscribableWatcher
     implements DirectoryWatcher {
+  @override
   String get directory => path;
 
   WindowsDirectoryWatcher(String directory)
@@ -29,7 +30,7 @@
   final List<FileSystemEvent> events = [];
   Timer timer;
 
-  void addEvent(FileSystemEvent event, void callback()) {
+  void addEvent(FileSystemEvent event, void Function() callback) {
     events.add(event);
     if (timer != null) {
       timer.cancel();
@@ -44,14 +45,19 @@
 
 class _WindowsDirectoryWatcher
     implements DirectoryWatcher, ManuallyClosedWatcher {
+  @override
   String get directory => path;
+  @override
   final String path;
 
+  @override
   Stream<WatchEvent> get events => _eventsController.stream;
   final _eventsController = StreamController<WatchEvent>.broadcast();
 
+  @override
   bool get isReady => _readyCompleter.isCompleted;
 
+  @override
   Future<void> get ready => _readyCompleter.future;
   final _readyCompleter = Completer();
 
@@ -94,6 +100,7 @@
     });
   }
 
+  @override
   void close() {
     if (_watchSubscription != null) _watchSubscription.cancel();
     if (_parentWatchSubscription != null) _parentWatchSubscription.cancel();
@@ -222,19 +229,19 @@
     // directory's full contents will be examined anyway, so we ignore such
     // events. Emitting them could cause useless or out-of-order events.
     var directories = unionAll(batch.map((event) {
-      if (!event.isDirectory) return Set<String>();
+      if (!event.isDirectory) return <String>{};
       if (event is FileSystemMoveEvent) {
-        return Set<String>.from([event.path, event.destination]);
+        return {event.path, event.destination};
       }
-      return Set<String>.from([event.path]);
+      return {event.path};
     }));
 
-    isInModifiedDirectory(String path) =>
+    bool isInModifiedDirectory(String path) =>
         directories.any((dir) => path != dir && path.startsWith(dir));
 
-    addEvent(String path, FileSystemEvent event) {
+    void addEvent(String path, FileSystemEvent event) {
       if (isInModifiedDirectory(path)) return;
-      eventsForPaths.putIfAbsent(path, () => Set<FileSystemEvent>()).add(event);
+      eventsForPaths.putIfAbsent(path, () => <FileSystemEvent>{}).add(event);
     }
 
     for (var event in batch) {
diff --git a/pkgs/watcher/lib/src/file_watcher/native.dart b/pkgs/watcher/lib/src/file_watcher/native.dart
index ff25eb7..7f466af 100644
--- a/pkgs/watcher/lib/src/file_watcher/native.dart
+++ b/pkgs/watcher/lib/src/file_watcher/native.dart
@@ -19,13 +19,17 @@
 }
 
 class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
+  @override
   final String path;
 
+  @override
   Stream<WatchEvent> get events => _eventsController.stream;
   final _eventsController = StreamController<WatchEvent>.broadcast();
 
+  @override
   bool get isReady => _readyCompleter.isCompleted;
 
+  @override
   Future get ready => _readyCompleter.future;
   final _readyCompleter = Completer();
 
@@ -57,7 +61,7 @@
     _eventsController.add(WatchEvent(ChangeType.MODIFY, path));
   }
 
-  _onDone() async {
+  void _onDone() async {
     var fileExists = await File(path).exists();
 
     // Check for this after checking whether the file exists because it's
@@ -77,6 +81,7 @@
     }
   }
 
+  @override
   void close() {
     if (_subscription != null) _subscription.cancel();
     _subscription = null;
diff --git a/pkgs/watcher/lib/src/file_watcher/polling.dart b/pkgs/watcher/lib/src/file_watcher/polling.dart
index e2bf5dd..11c0c6d 100644
--- a/pkgs/watcher/lib/src/file_watcher/polling.dart
+++ b/pkgs/watcher/lib/src/file_watcher/polling.dart
@@ -17,18 +17,22 @@
   PollingFileWatcher(String path, {Duration pollingDelay})
       : super(path, () {
           return _PollingFileWatcher(
-              path, pollingDelay != null ? pollingDelay : Duration(seconds: 1));
+              path, pollingDelay ?? Duration(seconds: 1));
         });
 }
 
 class _PollingFileWatcher implements FileWatcher, ManuallyClosedWatcher {
+  @override
   final String path;
 
+  @override
   Stream<WatchEvent> get events => _eventsController.stream;
   final _eventsController = StreamController<WatchEvent>.broadcast();
 
+  @override
   bool get isReady => _readyCompleter.isCompleted;
 
+  @override
   Future get ready => _readyCompleter.future;
   final _readyCompleter = Completer();
 
@@ -84,6 +88,7 @@
     }
   }
 
+  @override
   Future<void> close() async {
     _timer.cancel();
     await _eventsController.close();
diff --git a/pkgs/watcher/lib/src/path_set.dart b/pkgs/watcher/lib/src/path_set.dart
index d6983ff..41a0a39 100644
--- a/pkgs/watcher/lib/src/path_set.dart
+++ b/pkgs/watcher/lib/src/path_set.dart
@@ -61,7 +61,7 @@
         // the next level.
         var part = parts.removeFirst();
         var entry = dir.contents[part];
-        if (entry == null || entry.contents.isEmpty) return Set();
+        if (entry == null || entry.contents.isEmpty) return <String>{};
 
         partialPath = p.join(partialPath, part);
         var paths = recurse(entry, partialPath);
@@ -75,10 +75,10 @@
 
       // If there's only one component left in [path], we should remove it.
       var entry = dir.contents.remove(parts.first);
-      if (entry == null) return Set();
+      if (entry == null) return <String>{};
 
       if (entry.contents.isEmpty) {
-        return Set.from([p.join(root, path)]);
+        return {p.join(root, path)};
       }
 
       var set = _explicitPathsWithin(entry, path);
@@ -96,8 +96,8 @@
   ///
   /// [dirPath] should be the path to [dir].
   Set<String> _explicitPathsWithin(_Entry dir, String dirPath) {
-    var paths = Set<String>();
-    recurse(_Entry dir, String path) {
+    var paths = <String>{};
+    void recurse(_Entry dir, String path) {
       dir.contents.forEach((name, entry) {
         var entryPath = p.join(path, name);
         if (entry.isExplicit) paths.add(p.join(root, entryPath));
@@ -143,7 +143,7 @@
   List<String> get paths {
     var result = <String>[];
 
-    recurse(_Entry dir, String path) {
+    void recurse(_Entry dir, String path) {
       for (var name in dir.contents.keys) {
         var entry = dir.contents[name];
         var entryPath = p.join(path, name);
diff --git a/pkgs/watcher/lib/src/resubscribable.dart b/pkgs/watcher/lib/src/resubscribable.dart
index 8de3dfb..0719096 100644
--- a/pkgs/watcher/lib/src/resubscribable.dart
+++ b/pkgs/watcher/lib/src/resubscribable.dart
@@ -24,13 +24,17 @@
   /// The factory function that produces instances of the inner class.
   final ManuallyClosedWatcher Function() _factory;
 
+  @override
   final String path;
 
+  @override
   Stream<WatchEvent> get events => _eventsController.stream;
   StreamController<WatchEvent> _eventsController;
 
+  @override
   bool get isReady => _readyCompleter.isCompleted;
 
+  @override
   Future<void> get ready => _readyCompleter.future;
   var _readyCompleter = Completer<void>();
 
diff --git a/pkgs/watcher/lib/src/utils.dart b/pkgs/watcher/lib/src/utils.dart
index 676ae28..24b8184 100644
--- a/pkgs/watcher/lib/src/utils.dart
+++ b/pkgs/watcher/lib/src/utils.dart
@@ -12,13 +12,13 @@
   if (error is! FileSystemException) return false;
 
   // See dartbug.com/12461 and tests/standalone/io/directory_error_test.dart.
-  var notFoundCode = Platform.operatingSystem == "windows" ? 3 : 2;
+  var notFoundCode = Platform.operatingSystem == 'windows' ? 3 : 2;
   return error.osError.errorCode == notFoundCode;
 }
 
 /// Returns the union of all elements in each set in [sets].
 Set<T> unionAll<T>(Iterable<Set<T>> sets) =>
-    sets.fold(Set<T>(), (union, set) => union.union(set));
+    sets.fold(<T>{}, (union, set) => union.union(set));
 
 /// A stream transformer that batches all events that are sent at the same time.
 ///
@@ -28,6 +28,7 @@
 /// batches, this collates all the events that are received in "nearby"
 /// microtasks.
 class BatchedStreamTransformer<T> extends StreamTransformerBase<T, List<T>> {
+  @override
   Stream<List<T>> bind(Stream<T> input) {
     var batch = Queue<T>();
     return StreamTransformer<T, List<T>>.fromHandlers(
diff --git a/pkgs/watcher/lib/src/watch_event.dart b/pkgs/watcher/lib/src/watch_event.dart
index 94ee5cb..8b3fabb 100644
--- a/pkgs/watcher/lib/src/watch_event.dart
+++ b/pkgs/watcher/lib/src/watch_event.dart
@@ -12,22 +12,24 @@
 
   WatchEvent(this.type, this.path);
 
-  String toString() => "$type $path";
+  @override
+  String toString() => '$type $path';
 }
 
 /// Enum for what kind of change has happened to a file.
 class ChangeType {
   /// A new file has been added.
-  static const ADD = ChangeType("add");
+  static const ADD = ChangeType('add');
 
   /// A file has been removed.
-  static const REMOVE = ChangeType("remove");
+  static const REMOVE = ChangeType('remove');
 
   /// The contents of a file have changed.
-  static const MODIFY = ChangeType("modify");
+  static const MODIFY = ChangeType('modify');
 
   final String _name;
   const ChangeType(this._name);
 
+  @override
   String toString() => _name;
 }
diff --git a/pkgs/watcher/pubspec.yaml b/pkgs/watcher/pubspec.yaml
index f8315bc..9aa0eaf 100644
--- a/pkgs/watcher/pubspec.yaml
+++ b/pkgs/watcher/pubspec.yaml
@@ -1,5 +1,5 @@
 name: watcher
-version: 0.9.7+13
+version: 0.9.7+14-dev
 
 description: >-
   A file system watcher. It monitors changes to contents of directories and
@@ -8,7 +8,7 @@
 homepage: https://github.com/dart-lang/watcher
 
 environment:
-  sdk: '>=2.0.0 <3.0.0'
+  sdk: '>=2.2.0 <3.0.0'
 
 dependencies:
   async: '>=1.10.0 <3.0.0'
diff --git a/pkgs/watcher/test/directory_watcher/linux_test.dart b/pkgs/watcher/test/directory_watcher/linux_test.dart
index 0b81919..b4745a3 100644
--- a/pkgs/watcher/test/directory_watcher/linux_test.dart
+++ b/pkgs/watcher/test/directory_watcher/linux_test.dart
@@ -23,21 +23,21 @@
   test('emits events for many nested files moved out then immediately back in',
       () async {
     withPermutations(
-        (i, j, k) => writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
-    await startWatcher(path: "dir");
+        (i, j, k) => writeFile('dir/sub/sub-$i/sub-$j/file-$k.txt'));
+    await startWatcher(path: 'dir');
 
-    renameDir("dir/sub", "sub");
-    renameDir("sub", "dir/sub");
+    renameDir('dir/sub', 'sub');
+    renameDir('sub', 'dir/sub');
 
     await allowEither(() {
       inAnyOrder(withPermutations(
-          (i, j, k) => isRemoveEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isRemoveEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
 
       inAnyOrder(withPermutations(
-          (i, j, k) => isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isAddEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
     }, () {
       inAnyOrder(withPermutations(
-          (i, j, k) => isModifyEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isModifyEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
     });
   });
 }
diff --git a/pkgs/watcher/test/directory_watcher/mac_os_test.dart b/pkgs/watcher/test/directory_watcher/mac_os_test.dart
index 1470f71..b100f59 100644
--- a/pkgs/watcher/test/directory_watcher/mac_os_test.dart
+++ b/pkgs/watcher/test/directory_watcher/mac_os_test.dart
@@ -23,35 +23,35 @@
   test(
       'does not notify about the watched directory being deleted and '
       'recreated immediately before watching', () async {
-    createDir("dir");
-    writeFile("dir/old.txt");
-    deleteDir("dir");
-    createDir("dir");
+    createDir('dir');
+    writeFile('dir/old.txt');
+    deleteDir('dir');
+    createDir('dir');
 
-    await startWatcher(path: "dir");
-    writeFile("dir/newer.txt");
-    await expectAddEvent("dir/newer.txt");
+    await startWatcher(path: 'dir');
+    writeFile('dir/newer.txt');
+    await expectAddEvent('dir/newer.txt');
   });
 
   test('emits events for many nested files moved out then immediately back in',
       () async {
     withPermutations(
-        (i, j, k) => writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
+        (i, j, k) => writeFile('dir/sub/sub-$i/sub-$j/file-$k.txt'));
 
-    await startWatcher(path: "dir");
+    await startWatcher(path: 'dir');
 
-    renameDir("dir/sub", "sub");
-    renameDir("sub", "dir/sub");
+    renameDir('dir/sub', 'sub');
+    renameDir('sub', 'dir/sub');
 
     await allowEither(() {
       inAnyOrder(withPermutations(
-          (i, j, k) => isRemoveEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isRemoveEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
 
       inAnyOrder(withPermutations(
-          (i, j, k) => isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isAddEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
     }, () {
       inAnyOrder(withPermutations(
-          (i, j, k) => isModifyEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isModifyEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
     });
   });
 }
diff --git a/pkgs/watcher/test/directory_watcher/polling_test.dart b/pkgs/watcher/test/directory_watcher/polling_test.dart
index d64eb07..261d0e9 100644
--- a/pkgs/watcher/test/directory_watcher/polling_test.dart
+++ b/pkgs/watcher/test/directory_watcher/polling_test.dart
@@ -16,11 +16,11 @@
   sharedTests();
 
   test('does not notify if the modification time did not change', () async {
-    writeFile("a.txt", contents: "before");
-    writeFile("b.txt", contents: "before");
+    writeFile('a.txt', contents: 'before');
+    writeFile('b.txt', contents: 'before');
     await startWatcher();
-    writeFile("a.txt", contents: "after", updateModified: false);
-    writeFile("b.txt", contents: "after");
-    await expectModifyEvent("b.txt");
+    writeFile('a.txt', contents: 'after', updateModified: false);
+    writeFile('b.txt', contents: 'after');
+    await expectModifyEvent('b.txt');
   });
 }
diff --git a/pkgs/watcher/test/directory_watcher/shared.dart b/pkgs/watcher/test/directory_watcher/shared.dart
index a302c93..ebce488 100644
--- a/pkgs/watcher/test/directory_watcher/shared.dart
+++ b/pkgs/watcher/test/directory_watcher/shared.dart
@@ -10,130 +10,130 @@
 void sharedTests() {
   test('does not notify for files that already exist when started', () async {
     // Make some pre-existing files.
-    writeFile("a.txt");
-    writeFile("b.txt");
+    writeFile('a.txt');
+    writeFile('b.txt');
 
     await startWatcher();
 
     // Change one after the watcher is running.
-    writeFile("b.txt", contents: "modified");
+    writeFile('b.txt', contents: 'modified');
 
     // We should get a modify event for the changed file, but no add events
     // for them before this.
-    await expectModifyEvent("b.txt");
+    await expectModifyEvent('b.txt');
   });
 
   test('notifies when a file is added', () async {
     await startWatcher();
-    writeFile("file.txt");
-    await expectAddEvent("file.txt");
+    writeFile('file.txt');
+    await expectAddEvent('file.txt');
   });
 
   test('notifies when a file is modified', () async {
-    writeFile("file.txt");
+    writeFile('file.txt');
     await startWatcher();
-    writeFile("file.txt", contents: "modified");
-    await expectModifyEvent("file.txt");
+    writeFile('file.txt', contents: 'modified');
+    await expectModifyEvent('file.txt');
   });
 
   test('notifies when a file is removed', () async {
-    writeFile("file.txt");
+    writeFile('file.txt');
     await startWatcher();
-    deleteFile("file.txt");
-    await expectRemoveEvent("file.txt");
+    deleteFile('file.txt');
+    await expectRemoveEvent('file.txt');
   });
 
   test('notifies when a file is modified multiple times', () async {
-    writeFile("file.txt");
+    writeFile('file.txt');
     await startWatcher();
-    writeFile("file.txt", contents: "modified");
-    await expectModifyEvent("file.txt");
-    writeFile("file.txt", contents: "modified again");
-    await expectModifyEvent("file.txt");
+    writeFile('file.txt', contents: 'modified');
+    await expectModifyEvent('file.txt');
+    writeFile('file.txt', contents: 'modified again');
+    await expectModifyEvent('file.txt');
   });
 
   test('notifies even if the file contents are unchanged', () async {
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "before");
+    writeFile('a.txt', contents: 'same');
+    writeFile('b.txt', contents: 'before');
     await startWatcher();
 
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "after");
-    await inAnyOrder([isModifyEvent("a.txt"), isModifyEvent("b.txt")]);
+    writeFile('a.txt', contents: 'same');
+    writeFile('b.txt', contents: 'after');
+    await inAnyOrder([isModifyEvent('a.txt'), isModifyEvent('b.txt')]);
   });
 
   test('when the watched directory is deleted, removes all files', () async {
-    writeFile("dir/a.txt");
-    writeFile("dir/b.txt");
+    writeFile('dir/a.txt');
+    writeFile('dir/b.txt');
 
-    await startWatcher(path: "dir");
+    await startWatcher(path: 'dir');
 
-    deleteDir("dir");
-    await inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
+    deleteDir('dir');
+    await inAnyOrder([isRemoveEvent('dir/a.txt'), isRemoveEvent('dir/b.txt')]);
   });
 
   test('when the watched directory is moved, removes all files', () async {
-    writeFile("dir/a.txt");
-    writeFile("dir/b.txt");
+    writeFile('dir/a.txt');
+    writeFile('dir/b.txt');
 
-    await startWatcher(path: "dir");
+    await startWatcher(path: 'dir');
 
-    renameDir("dir", "moved_dir");
-    createDir("dir");
-    await inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
+    renameDir('dir', 'moved_dir');
+    createDir('dir');
+    await inAnyOrder([isRemoveEvent('dir/a.txt'), isRemoveEvent('dir/b.txt')]);
   });
 
   // Regression test for b/30768513.
   test(
       "doesn't crash when the directory is moved immediately after a subdir "
-      "is added", () async {
-    writeFile("dir/a.txt");
-    writeFile("dir/b.txt");
+      'is added', () async {
+    writeFile('dir/a.txt');
+    writeFile('dir/b.txt');
 
-    await startWatcher(path: "dir");
+    await startWatcher(path: 'dir');
 
-    createDir("dir/subdir");
-    renameDir("dir", "moved_dir");
-    createDir("dir");
-    await inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
+    createDir('dir/subdir');
+    renameDir('dir', 'moved_dir');
+    createDir('dir');
+    await inAnyOrder([isRemoveEvent('dir/a.txt'), isRemoveEvent('dir/b.txt')]);
   });
 
-  group("moves", () {
+  group('moves', () {
     test('notifies when a file is moved within the watched directory',
         () async {
-      writeFile("old.txt");
+      writeFile('old.txt');
       await startWatcher();
-      renameFile("old.txt", "new.txt");
+      renameFile('old.txt', 'new.txt');
 
-      await inAnyOrder([isAddEvent("new.txt"), isRemoveEvent("old.txt")]);
+      await inAnyOrder([isAddEvent('new.txt'), isRemoveEvent('old.txt')]);
     });
 
     test('notifies when a file is moved from outside the watched directory',
         () async {
-      writeFile("old.txt");
-      createDir("dir");
-      await startWatcher(path: "dir");
+      writeFile('old.txt');
+      createDir('dir');
+      await startWatcher(path: 'dir');
 
-      renameFile("old.txt", "dir/new.txt");
-      await expectAddEvent("dir/new.txt");
+      renameFile('old.txt', 'dir/new.txt');
+      await expectAddEvent('dir/new.txt');
     });
 
     test('notifies when a file is moved outside the watched directory',
         () async {
-      writeFile("dir/old.txt");
-      await startWatcher(path: "dir");
+      writeFile('dir/old.txt');
+      await startWatcher(path: 'dir');
 
-      renameFile("dir/old.txt", "new.txt");
-      await expectRemoveEvent("dir/old.txt");
+      renameFile('dir/old.txt', 'new.txt');
+      await expectRemoveEvent('dir/old.txt');
     });
 
     test('notifies when a file is moved onto an existing one', () async {
-      writeFile("from.txt");
-      writeFile("to.txt");
+      writeFile('from.txt');
+      writeFile('to.txt');
       await startWatcher();
 
-      renameFile("from.txt", "to.txt");
-      await inAnyOrder([isRemoveEvent("from.txt"), isModifyEvent("to.txt")]);
+      renameFile('from.txt', 'to.txt');
+      await inAnyOrder([isRemoveEvent('from.txt'), isModifyEvent('to.txt')]);
     });
   });
 
@@ -144,198 +144,198 @@
   // separate batches, and the watcher will report them as though they occurred
   // far apart in time, so each of these tests has a "backup case" to allow for
   // that as well.
-  group("clustered changes", () {
+  group('clustered changes', () {
     test("doesn't notify when a file is created and then immediately removed",
         () async {
-      writeFile("test.txt");
+      writeFile('test.txt');
       await startWatcher();
-      writeFile("file.txt");
-      deleteFile("file.txt");
+      writeFile('file.txt');
+      deleteFile('file.txt');
 
       // Backup case.
       startClosingEventStream();
       await allowEvents(() {
-        expectAddEvent("file.txt");
-        expectRemoveEvent("file.txt");
+        expectAddEvent('file.txt');
+        expectRemoveEvent('file.txt');
       });
     });
 
     test(
-        "reports a modification when a file is deleted and then immediately "
-        "recreated", () async {
-      writeFile("file.txt");
+        'reports a modification when a file is deleted and then immediately '
+        'recreated', () async {
+      writeFile('file.txt');
       await startWatcher();
 
-      deleteFile("file.txt");
-      writeFile("file.txt", contents: "re-created");
+      deleteFile('file.txt');
+      writeFile('file.txt', contents: 're-created');
 
       await allowEither(() {
-        expectModifyEvent("file.txt");
+        expectModifyEvent('file.txt');
       }, () {
         // Backup case.
-        expectRemoveEvent("file.txt");
-        expectAddEvent("file.txt");
+        expectRemoveEvent('file.txt');
+        expectAddEvent('file.txt');
       });
     });
 
     test(
-        "reports a modification when a file is moved and then immediately "
-        "recreated", () async {
-      writeFile("old.txt");
+        'reports a modification when a file is moved and then immediately '
+        'recreated', () async {
+      writeFile('old.txt');
       await startWatcher();
 
-      renameFile("old.txt", "new.txt");
-      writeFile("old.txt", contents: "re-created");
+      renameFile('old.txt', 'new.txt');
+      writeFile('old.txt', contents: 're-created');
 
       await allowEither(() {
-        inAnyOrder([isModifyEvent("old.txt"), isAddEvent("new.txt")]);
+        inAnyOrder([isModifyEvent('old.txt'), isAddEvent('new.txt')]);
       }, () {
         // Backup case.
-        expectRemoveEvent("old.txt");
-        expectAddEvent("new.txt");
-        expectAddEvent("old.txt");
+        expectRemoveEvent('old.txt');
+        expectAddEvent('new.txt');
+        expectAddEvent('old.txt');
       });
     });
 
     test(
-        "reports a removal when a file is modified and then immediately "
-        "removed", () async {
-      writeFile("file.txt");
+        'reports a removal when a file is modified and then immediately '
+        'removed', () async {
+      writeFile('file.txt');
       await startWatcher();
 
-      writeFile("file.txt", contents: "modified");
-      deleteFile("file.txt");
+      writeFile('file.txt', contents: 'modified');
+      deleteFile('file.txt');
 
       // Backup case.
-      await allowModifyEvent("file.txt");
+      await allowModifyEvent('file.txt');
 
-      await expectRemoveEvent("file.txt");
+      await expectRemoveEvent('file.txt');
     });
 
-    test("reports an add when a file is added and then immediately modified",
+    test('reports an add when a file is added and then immediately modified',
         () async {
       await startWatcher();
 
-      writeFile("file.txt");
-      writeFile("file.txt", contents: "modified");
+      writeFile('file.txt');
+      writeFile('file.txt', contents: 'modified');
 
-      await expectAddEvent("file.txt");
+      await expectAddEvent('file.txt');
 
       // Backup case.
       startClosingEventStream();
-      await allowModifyEvent("file.txt");
+      await allowModifyEvent('file.txt');
     });
   });
 
-  group("subdirectories", () {
+  group('subdirectories', () {
     test('watches files in subdirectories', () async {
       await startWatcher();
-      writeFile("a/b/c/d/file.txt");
-      await expectAddEvent("a/b/c/d/file.txt");
+      writeFile('a/b/c/d/file.txt');
+      await expectAddEvent('a/b/c/d/file.txt');
     });
 
     test(
         'notifies when a subdirectory is moved within the watched directory '
         'and then its contents are modified', () async {
-      writeFile("old/file.txt");
+      writeFile('old/file.txt');
       await startWatcher();
 
-      renameDir("old", "new");
+      renameDir('old', 'new');
       await inAnyOrder(
-          [isRemoveEvent("old/file.txt"), isAddEvent("new/file.txt")]);
+          [isRemoveEvent('old/file.txt'), isAddEvent('new/file.txt')]);
 
-      writeFile("new/file.txt", contents: "modified");
-      await expectModifyEvent("new/file.txt");
+      writeFile('new/file.txt', contents: 'modified');
+      await expectModifyEvent('new/file.txt');
     });
 
     test('notifies when a file is replaced by a subdirectory', () async {
-      writeFile("new");
-      writeFile("old/file.txt");
+      writeFile('new');
+      writeFile('old/file.txt');
       await startWatcher();
 
-      deleteFile("new");
-      renameDir("old", "new");
+      deleteFile('new');
+      renameDir('old', 'new');
       await inAnyOrder([
-        isRemoveEvent("new"),
-        isRemoveEvent("old/file.txt"),
-        isAddEvent("new/file.txt")
+        isRemoveEvent('new'),
+        isRemoveEvent('old/file.txt'),
+        isAddEvent('new/file.txt')
       ]);
     });
 
     test('notifies when a subdirectory is replaced by a file', () async {
-      writeFile("old");
-      writeFile("new/file.txt");
+      writeFile('old');
+      writeFile('new/file.txt');
       await startWatcher();
 
-      renameDir("new", "newer");
-      renameFile("old", "new");
+      renameDir('new', 'newer');
+      renameFile('old', 'new');
       await inAnyOrder([
-        isRemoveEvent("new/file.txt"),
-        isAddEvent("newer/file.txt"),
-        isRemoveEvent("old"),
-        isAddEvent("new")
+        isRemoveEvent('new/file.txt'),
+        isAddEvent('newer/file.txt'),
+        isRemoveEvent('old'),
+        isAddEvent('new')
       ]);
     }, onPlatform: {
-      "mac-os": Skip("https://github.com/dart-lang/watcher/issues/21")
+      'mac-os': Skip('https://github.com/dart-lang/watcher/issues/21')
     });
 
     test('emits events for many nested files added at once', () async {
-      withPermutations((i, j, k) => writeFile("sub/sub-$i/sub-$j/file-$k.txt"));
+      withPermutations((i, j, k) => writeFile('sub/sub-$i/sub-$j/file-$k.txt'));
 
-      createDir("dir");
-      await startWatcher(path: "dir");
-      renameDir("sub", "dir/sub");
+      createDir('dir');
+      await startWatcher(path: 'dir');
+      renameDir('sub', 'dir/sub');
 
       await inAnyOrder(withPermutations(
-          (i, j, k) => isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isAddEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
     });
 
     test('emits events for many nested files removed at once', () async {
       withPermutations(
-          (i, j, k) => writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
+          (i, j, k) => writeFile('dir/sub/sub-$i/sub-$j/file-$k.txt'));
 
-      createDir("dir");
-      await startWatcher(path: "dir");
+      createDir('dir');
+      await startWatcher(path: 'dir');
 
       // Rename the directory rather than deleting it because native watchers
       // report a rename as a single DELETE event for the directory, whereas
       // they report recursive deletion with DELETE events for every file in the
       // directory.
-      renameDir("dir/sub", "sub");
+      renameDir('dir/sub', 'sub');
 
       await inAnyOrder(withPermutations(
-          (i, j, k) => isRemoveEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
+          (i, j, k) => isRemoveEvent('dir/sub/sub-$i/sub-$j/file-$k.txt')));
     });
 
     test('emits events for many nested files moved at once', () async {
       withPermutations(
-          (i, j, k) => writeFile("dir/old/sub-$i/sub-$j/file-$k.txt"));
+          (i, j, k) => writeFile('dir/old/sub-$i/sub-$j/file-$k.txt'));
 
-      createDir("dir");
-      await startWatcher(path: "dir");
-      renameDir("dir/old", "dir/new");
+      createDir('dir');
+      await startWatcher(path: 'dir');
+      renameDir('dir/old', 'dir/new');
 
       await inAnyOrder(unionAll(withPermutations((i, j, k) {
-        return Set.from([
-          isRemoveEvent("dir/old/sub-$i/sub-$j/file-$k.txt"),
-          isAddEvent("dir/new/sub-$i/sub-$j/file-$k.txt")
-        ]);
+        return {
+          isRemoveEvent('dir/old/sub-$i/sub-$j/file-$k.txt'),
+          isAddEvent('dir/new/sub-$i/sub-$j/file-$k.txt')
+        };
       })));
     });
 
     test(
-        "emits events for many files added at once in a subdirectory with the "
-        "same name as a removed file", () async {
-      writeFile("dir/sub");
-      withPermutations((i, j, k) => writeFile("old/sub-$i/sub-$j/file-$k.txt"));
-      await startWatcher(path: "dir");
+        'emits events for many files added at once in a subdirectory with the '
+        'same name as a removed file', () async {
+      writeFile('dir/sub');
+      withPermutations((i, j, k) => writeFile('old/sub-$i/sub-$j/file-$k.txt'));
+      await startWatcher(path: 'dir');
 
-      deleteFile("dir/sub");
-      renameDir("old", "dir/sub");
+      deleteFile('dir/sub');
+      renameDir('old', 'dir/sub');
 
       var events = withPermutations(
-          (i, j, k) => isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt"));
-      events.add(isRemoveEvent("dir/sub"));
+          (i, j, k) => isAddEvent('dir/sub/sub-$i/sub-$j/file-$k.txt'));
+      events.add(isRemoveEvent('dir/sub'));
       await inAnyOrder(events);
     });
   });
diff --git a/pkgs/watcher/test/directory_watcher/windows_test.dart b/pkgs/watcher/test/directory_watcher/windows_test.dart
index 7931fa8..6ea412f 100644
--- a/pkgs/watcher/test/directory_watcher/windows_test.dart
+++ b/pkgs/watcher/test/directory_watcher/windows_test.dart
@@ -16,9 +16,9 @@
 
   // TODO(grouma) - renable when https://github.com/dart-lang/sdk/issues/31760
   // is resolved.
-  group("Shared Tests:", () {
+  group('Shared Tests:', () {
     sharedTests();
-  }, skip: "SDK issue see - https://github.com/dart-lang/sdk/issues/31760");
+  }, skip: 'SDK issue see - https://github.com/dart-lang/sdk/issues/31760');
 
   test('DirectoryWatcher creates a WindowsDirectoryWatcher on Windows', () {
     expect(DirectoryWatcher('.'), TypeMatcher<WindowsDirectoryWatcher>());
diff --git a/pkgs/watcher/test/file_watcher/native_test.dart b/pkgs/watcher/test/file_watcher/native_test.dart
index 2417dae..b59d4ed 100644
--- a/pkgs/watcher/test/file_watcher/native_test.dart
+++ b/pkgs/watcher/test/file_watcher/native_test.dart
@@ -14,7 +14,7 @@
   watcherFactory = (file) => NativeFileWatcher(file);
 
   setUp(() {
-    writeFile("file.txt");
+    writeFile('file.txt');
   });
 
   sharedTests();
diff --git a/pkgs/watcher/test/file_watcher/polling_test.dart b/pkgs/watcher/test/file_watcher/polling_test.dart
index 9492f65..b83d44f 100644
--- a/pkgs/watcher/test/file_watcher/polling_test.dart
+++ b/pkgs/watcher/test/file_watcher/polling_test.dart
@@ -15,7 +15,7 @@
       PollingFileWatcher(file, pollingDelay: Duration(milliseconds: 100));
 
   setUp(() {
-    writeFile("file.txt");
+    writeFile('file.txt');
   });
 
   sharedTests();
diff --git a/pkgs/watcher/test/file_watcher/shared.dart b/pkgs/watcher/test/file_watcher/shared.dart
index eefe5df..c837a21 100644
--- a/pkgs/watcher/test/file_watcher/shared.dart
+++ b/pkgs/watcher/test/file_watcher/shared.dart
@@ -10,60 +10,60 @@
 
 void sharedTests() {
   test("doesn't notify if the file isn't modified", () async {
-    await startWatcher(path: "file.txt");
+    await startWatcher(path: 'file.txt');
     await pumpEventQueue();
-    deleteFile("file.txt");
-    await expectRemoveEvent("file.txt");
+    deleteFile('file.txt');
+    await expectRemoveEvent('file.txt');
   });
 
-  test("notifies when a file is modified", () async {
-    await startWatcher(path: "file.txt");
-    writeFile("file.txt", contents: "modified");
-    await expectModifyEvent("file.txt");
+  test('notifies when a file is modified', () async {
+    await startWatcher(path: 'file.txt');
+    writeFile('file.txt', contents: 'modified');
+    await expectModifyEvent('file.txt');
   });
 
-  test("notifies when a file is removed", () async {
-    await startWatcher(path: "file.txt");
-    deleteFile("file.txt");
-    await expectRemoveEvent("file.txt");
+  test('notifies when a file is removed', () async {
+    await startWatcher(path: 'file.txt');
+    deleteFile('file.txt');
+    await expectRemoveEvent('file.txt');
   });
 
-  test("notifies when a file is modified multiple times", () async {
-    await startWatcher(path: "file.txt");
-    writeFile("file.txt", contents: "modified");
-    await expectModifyEvent("file.txt");
-    writeFile("file.txt", contents: "modified again");
-    await expectModifyEvent("file.txt");
+  test('notifies when a file is modified multiple times', () async {
+    await startWatcher(path: 'file.txt');
+    writeFile('file.txt', contents: 'modified');
+    await expectModifyEvent('file.txt');
+    writeFile('file.txt', contents: 'modified again');
+    await expectModifyEvent('file.txt');
   });
 
-  test("notifies even if the file contents are unchanged", () async {
-    await startWatcher(path: "file.txt");
-    writeFile("file.txt");
-    await expectModifyEvent("file.txt");
+  test('notifies even if the file contents are unchanged', () async {
+    await startWatcher(path: 'file.txt');
+    writeFile('file.txt');
+    await expectModifyEvent('file.txt');
   });
 
-  test("emits a remove event when the watched file is moved away", () async {
-    await startWatcher(path: "file.txt");
-    renameFile("file.txt", "new.txt");
-    await expectRemoveEvent("file.txt");
+  test('emits a remove event when the watched file is moved away', () async {
+    await startWatcher(path: 'file.txt');
+    renameFile('file.txt', 'new.txt');
+    await expectRemoveEvent('file.txt');
   });
 
   test(
-      "emits a modify event when another file is moved on top of the watched "
-      "file", () async {
-    writeFile("old.txt");
-    await startWatcher(path: "file.txt");
-    renameFile("old.txt", "file.txt");
-    await expectModifyEvent("file.txt");
+      'emits a modify event when another file is moved on top of the watched '
+      'file', () async {
+    writeFile('old.txt');
+    await startWatcher(path: 'file.txt');
+    renameFile('old.txt', 'file.txt');
+    await expectModifyEvent('file.txt');
   });
 
   // Regression test for a race condition.
-  test("closes the watcher immediately after deleting the file", () async {
-    writeFile("old.txt");
-    var watcher = createWatcher(path: "file.txt");
+  test('closes the watcher immediately after deleting the file', () async {
+    writeFile('old.txt');
+    var watcher = createWatcher(path: 'file.txt');
     var sub = watcher.events.listen(null);
 
-    deleteFile("file.txt");
+    deleteFile('file.txt');
     await Future.delayed(Duration(milliseconds: 10));
     await sub.cancel();
   });
diff --git a/pkgs/watcher/test/no_subscription/mac_os_test.dart b/pkgs/watcher/test/no_subscription/mac_os_test.dart
index 5ffb117..f227077 100644
--- a/pkgs/watcher/test/no_subscription/mac_os_test.dart
+++ b/pkgs/watcher/test/no_subscription/mac_os_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @TestOn('mac-os')
-@Skip("Flaky due to sdk#23877")
+@Skip('Flaky due to sdk#23877')
 
 import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/mac_os.dart';
diff --git a/pkgs/watcher/test/no_subscription/shared.dart b/pkgs/watcher/test/no_subscription/shared.dart
index e82692e..bcdba5f 100644
--- a/pkgs/watcher/test/no_subscription/shared.dart
+++ b/pkgs/watcher/test/no_subscription/shared.dart
@@ -19,7 +19,7 @@
     unawaited(queue.hasNext);
 
     var future =
-        expectLater(queue, emits(isWatchEvent(ChangeType.ADD, "file.txt")));
+        expectLater(queue, emits(isWatchEvent(ChangeType.ADD, 'file.txt')));
     expect(queue, neverEmits(anything));
 
     await watcher.ready;
@@ -32,18 +32,18 @@
     await queue.cancel(immediate: true);
 
     // Now write a file while we aren't listening.
-    writeFile("unwatched.txt");
+    writeFile('unwatched.txt');
 
     queue = StreamQueue(watcher.events);
     future =
-        expectLater(queue, emits(isWatchEvent(ChangeType.ADD, "added.txt")));
-    expect(queue, neverEmits(isWatchEvent(ChangeType.ADD, "unwatched.txt")));
+        expectLater(queue, emits(isWatchEvent(ChangeType.ADD, 'added.txt')));
+    expect(queue, neverEmits(isWatchEvent(ChangeType.ADD, 'unwatched.txt')));
 
     // Wait until the watcher is ready to dispatch events again.
     await watcher.ready;
 
     // And add a third file.
-    writeFile("added.txt");
+    writeFile('added.txt');
 
     // Wait until we get an event for the third file.
     await future;
diff --git a/pkgs/watcher/test/path_set_test.dart b/pkgs/watcher/test/path_set_test.dart
index 9ca4181..25cf969 100644
--- a/pkgs/watcher/test/path_set_test.dart
+++ b/pkgs/watcher/test/path_set_test.dart
@@ -16,210 +16,210 @@
 
 void main() {
   PathSet paths;
-  setUp(() => paths = PathSet("root"));
+  setUp(() => paths = PathSet('root'));
 
-  group("adding a path", () {
-    test("stores the path in the set", () {
-      paths.add("root/path/to/file");
-      expect(paths, containsPath("root/path/to/file"));
+  group('adding a path', () {
+    test('stores the path in the set', () {
+      paths.add('root/path/to/file');
+      expect(paths, containsPath('root/path/to/file'));
     });
 
     test("that's a subdir of another path keeps both in the set", () {
-      paths.add("root/path");
-      paths.add("root/path/to/file");
-      expect(paths, containsPath("root/path"));
-      expect(paths, containsPath("root/path/to/file"));
+      paths.add('root/path');
+      paths.add('root/path/to/file');
+      expect(paths, containsPath('root/path'));
+      expect(paths, containsPath('root/path/to/file'));
     });
 
     test("that's not normalized normalizes the path before storing it", () {
-      paths.add("root/../root/path/to/../to/././file");
-      expect(paths, containsPath("root/path/to/file"));
+      paths.add('root/../root/path/to/../to/././file');
+      expect(paths, containsPath('root/path/to/file'));
     });
 
     test("that's absolute normalizes the path before storing it", () {
-      paths.add(p.absolute("root/path/to/file"));
-      expect(paths, containsPath("root/path/to/file"));
+      paths.add(p.absolute('root/path/to/file'));
+      expect(paths, containsPath('root/path/to/file'));
     });
   });
 
-  group("removing a path", () {
+  group('removing a path', () {
     test("that's in the set removes and returns that path", () {
-      paths.add("root/path/to/file");
-      expect(paths.remove("root/path/to/file"),
-          unorderedEquals([p.normalize("root/path/to/file")]));
-      expect(paths, isNot(containsPath("root/path/to/file")));
+      paths.add('root/path/to/file');
+      expect(paths.remove('root/path/to/file'),
+          unorderedEquals([p.normalize('root/path/to/file')]));
+      expect(paths, isNot(containsPath('root/path/to/file')));
     });
 
     test("that's not in the set returns an empty set", () {
-      paths.add("root/path/to/file");
-      expect(paths.remove("root/path/to/nothing"), isEmpty);
+      paths.add('root/path/to/file');
+      expect(paths.remove('root/path/to/nothing'), isEmpty);
     });
 
     test("that's a directory removes and returns all files beneath it", () {
-      paths.add("root/outside");
-      paths.add("root/path/to/one");
-      paths.add("root/path/to/two");
-      paths.add("root/path/to/sub/three");
+      paths.add('root/outside');
+      paths.add('root/path/to/one');
+      paths.add('root/path/to/two');
+      paths.add('root/path/to/sub/three');
 
       expect(
-          paths.remove("root/path"),
+          paths.remove('root/path'),
           unorderedEquals([
-            "root/path/to/one",
-            "root/path/to/two",
-            "root/path/to/sub/three"
+            'root/path/to/one',
+            'root/path/to/two',
+            'root/path/to/sub/three'
           ].map(p.normalize)));
 
-      expect(paths, containsPath("root/outside"));
-      expect(paths, isNot(containsPath("root/path/to/one")));
-      expect(paths, isNot(containsPath("root/path/to/two")));
-      expect(paths, isNot(containsPath("root/path/to/sub/three")));
+      expect(paths, containsPath('root/outside'));
+      expect(paths, isNot(containsPath('root/path/to/one')));
+      expect(paths, isNot(containsPath('root/path/to/two')));
+      expect(paths, isNot(containsPath('root/path/to/sub/three')));
     });
 
     test(
         "that's a directory in the set removes and returns it and all files "
-        "beneath it", () {
-      paths.add("root/path");
-      paths.add("root/path/to/one");
-      paths.add("root/path/to/two");
-      paths.add("root/path/to/sub/three");
+        'beneath it', () {
+      paths.add('root/path');
+      paths.add('root/path/to/one');
+      paths.add('root/path/to/two');
+      paths.add('root/path/to/sub/three');
 
       expect(
-          paths.remove("root/path"),
+          paths.remove('root/path'),
           unorderedEquals([
-            "root/path",
-            "root/path/to/one",
-            "root/path/to/two",
-            "root/path/to/sub/three"
+            'root/path',
+            'root/path/to/one',
+            'root/path/to/two',
+            'root/path/to/sub/three'
           ].map(p.normalize)));
 
-      expect(paths, isNot(containsPath("root/path")));
-      expect(paths, isNot(containsPath("root/path/to/one")));
-      expect(paths, isNot(containsPath("root/path/to/two")));
-      expect(paths, isNot(containsPath("root/path/to/sub/three")));
+      expect(paths, isNot(containsPath('root/path')));
+      expect(paths, isNot(containsPath('root/path/to/one')));
+      expect(paths, isNot(containsPath('root/path/to/two')));
+      expect(paths, isNot(containsPath('root/path/to/sub/three')));
     });
 
     test("that's not normalized removes and returns the normalized path", () {
-      paths.add("root/path/to/file");
-      expect(paths.remove("root/../root/path/to/../to/./file"),
-          unorderedEquals([p.normalize("root/path/to/file")]));
+      paths.add('root/path/to/file');
+      expect(paths.remove('root/../root/path/to/../to/./file'),
+          unorderedEquals([p.normalize('root/path/to/file')]));
     });
 
     test("that's absolute removes and returns the normalized path", () {
-      paths.add("root/path/to/file");
-      expect(paths.remove(p.absolute("root/path/to/file")),
-          unorderedEquals([p.normalize("root/path/to/file")]));
+      paths.add('root/path/to/file');
+      expect(paths.remove(p.absolute('root/path/to/file')),
+          unorderedEquals([p.normalize('root/path/to/file')]));
     });
   });
 
-  group("containsPath()", () {
-    test("returns false for a non-existent path", () {
-      paths.add("root/path/to/file");
-      expect(paths, isNot(containsPath("root/path/to/nothing")));
+  group('containsPath()', () {
+    test('returns false for a non-existent path', () {
+      paths.add('root/path/to/file');
+      expect(paths, isNot(containsPath('root/path/to/nothing')));
     });
 
     test("returns false for a directory that wasn't added explicitly", () {
-      paths.add("root/path/to/file");
-      expect(paths, isNot(containsPath("root/path")));
+      paths.add('root/path/to/file');
+      expect(paths, isNot(containsPath('root/path')));
     });
 
-    test("returns true for a directory that was added explicitly", () {
-      paths.add("root/path");
-      paths.add("root/path/to/file");
-      expect(paths, containsPath("root/path"));
+    test('returns true for a directory that was added explicitly', () {
+      paths.add('root/path');
+      paths.add('root/path/to/file');
+      expect(paths, containsPath('root/path'));
     });
 
-    test("with a non-normalized path normalizes the path before looking it up",
+    test('with a non-normalized path normalizes the path before looking it up',
         () {
-      paths.add("root/path/to/file");
-      expect(paths, containsPath("root/../root/path/to/../to/././file"));
+      paths.add('root/path/to/file');
+      expect(paths, containsPath('root/../root/path/to/../to/././file'));
     });
 
-    test("with an absolute path normalizes the path before looking it up", () {
-      paths.add("root/path/to/file");
-      expect(paths, containsPath(p.absolute("root/path/to/file")));
+    test('with an absolute path normalizes the path before looking it up', () {
+      paths.add('root/path/to/file');
+      expect(paths, containsPath(p.absolute('root/path/to/file')));
     });
   });
 
-  group("containsDir()", () {
-    test("returns true for a directory that was added implicitly", () {
-      paths.add("root/path/to/file");
-      expect(paths, containsDir("root/path"));
-      expect(paths, containsDir("root/path/to"));
+  group('containsDir()', () {
+    test('returns true for a directory that was added implicitly', () {
+      paths.add('root/path/to/file');
+      expect(paths, containsDir('root/path'));
+      expect(paths, containsDir('root/path/to'));
     });
 
-    test("returns true for a directory that was added explicitly", () {
-      paths.add("root/path");
-      paths.add("root/path/to/file");
-      expect(paths, containsDir("root/path"));
+    test('returns true for a directory that was added explicitly', () {
+      paths.add('root/path');
+      paths.add('root/path/to/file');
+      expect(paths, containsDir('root/path'));
     });
 
     test("returns false for a directory that wasn't added", () {
-      expect(paths, isNot(containsDir("root/nothing")));
+      expect(paths, isNot(containsDir('root/nothing')));
     });
 
-    test("returns false for a non-directory path that was added", () {
-      paths.add("root/path/to/file");
-      expect(paths, isNot(containsDir("root/path/to/file")));
+    test('returns false for a non-directory path that was added', () {
+      paths.add('root/path/to/file');
+      expect(paths, isNot(containsDir('root/path/to/file')));
     });
 
     test(
-        "returns false for a directory that was added implicitly and then "
-        "removed implicitly", () {
-      paths.add("root/path/to/file");
-      paths.remove("root/path/to/file");
-      expect(paths, isNot(containsDir("root/path")));
+        'returns false for a directory that was added implicitly and then '
+        'removed implicitly', () {
+      paths.add('root/path/to/file');
+      paths.remove('root/path/to/file');
+      expect(paths, isNot(containsDir('root/path')));
     });
 
     test(
-        "returns false for a directory that was added explicitly whose "
-        "children were then removed", () {
-      paths.add("root/path");
-      paths.add("root/path/to/file");
-      paths.remove("root/path/to/file");
-      expect(paths, isNot(containsDir("root/path")));
+        'returns false for a directory that was added explicitly whose '
+        'children were then removed', () {
+      paths.add('root/path');
+      paths.add('root/path/to/file');
+      paths.remove('root/path/to/file');
+      expect(paths, isNot(containsDir('root/path')));
     });
 
-    test("with a non-normalized path normalizes the path before looking it up",
+    test('with a non-normalized path normalizes the path before looking it up',
         () {
-      paths.add("root/path/to/file");
-      expect(paths, containsDir("root/../root/path/to/../to/."));
+      paths.add('root/path/to/file');
+      expect(paths, containsDir('root/../root/path/to/../to/.'));
     });
 
-    test("with an absolute path normalizes the path before looking it up", () {
-      paths.add("root/path/to/file");
-      expect(paths, containsDir(p.absolute("root/path")));
+    test('with an absolute path normalizes the path before looking it up', () {
+      paths.add('root/path/to/file');
+      expect(paths, containsDir(p.absolute('root/path')));
     });
   });
 
-  group("paths", () {
-    test("returns paths added to the set", () {
-      paths.add("root/path");
-      paths.add("root/path/to/one");
-      paths.add("root/path/to/two");
+  group('paths', () {
+    test('returns paths added to the set', () {
+      paths.add('root/path');
+      paths.add('root/path/to/one');
+      paths.add('root/path/to/two');
 
       expect(
           paths.paths,
           unorderedEquals([
-            "root/path",
-            "root/path/to/one",
-            "root/path/to/two",
+            'root/path',
+            'root/path/to/one',
+            'root/path/to/two',
           ].map(p.normalize)));
     });
 
     test("doesn't return paths removed from the set", () {
-      paths.add("root/path/to/one");
-      paths.add("root/path/to/two");
-      paths.remove("root/path/to/two");
+      paths.add('root/path/to/one');
+      paths.add('root/path/to/two');
+      paths.remove('root/path/to/two');
 
-      expect(paths.paths, unorderedEquals([p.normalize("root/path/to/one")]));
+      expect(paths.paths, unorderedEquals([p.normalize('root/path/to/one')]));
     });
   });
 
-  group("clear", () {
-    test("removes all paths from the set", () {
-      paths.add("root/path");
-      paths.add("root/path/to/one");
-      paths.add("root/path/to/two");
+  group('clear', () {
+    test('removes all paths from the set', () {
+      paths.add('root/path');
+      paths.add('root/path/to/one');
+      paths.add('root/path/to/two');
 
       paths.clear();
       expect(paths.paths, isEmpty);
diff --git a/pkgs/watcher/test/utils.dart b/pkgs/watcher/test/utils.dart
index 2e0ad01..fe86407 100644
--- a/pkgs/watcher/test/utils.dart
+++ b/pkgs/watcher/test/utils.dart
@@ -58,7 +58,7 @@
     path = p.normalize(p.relative(path, from: d.sandbox));
 
     // Make sure we got a path in the sandbox.
-    assert(p.isRelative(path) && !path.startsWith(".."));
+    assert(p.isRelative(path) && !path.startsWith('..'));
 
     var mtime = _mockFileModificationTimes[path];
     return DateTime.fromMillisecondsSinceEpoch(mtime ?? 0);
@@ -92,9 +92,9 @@
 /// single stream matcher.
 ///
 /// The returned matcher will match each of the collected matchers in order.
-StreamMatcher _collectStreamMatcher(block()) {
+StreamMatcher _collectStreamMatcher(void Function() block) {
   var oldStreamMatchers = _collectedStreamMatchers;
-  _collectedStreamMatchers = List<StreamMatcher>();
+  _collectedStreamMatchers = <StreamMatcher>[];
   try {
     block();
     return emitsInOrder(_collectedStreamMatchers);
@@ -128,15 +128,16 @@
 /// will match the emitted events.
 ///
 /// If both blocks match, the one that consumed more events will be used.
-Future allowEither(block1(), block2()) => _expectOrCollect(
-    emitsAnyOf([_collectStreamMatcher(block1), _collectStreamMatcher(block2)]));
+Future allowEither(void Function() block1, void Function() block2) =>
+    _expectOrCollect(emitsAnyOf(
+        [_collectStreamMatcher(block1), _collectStreamMatcher(block2)]));
 
 /// Allows the expectations established in [block] to match the emitted events.
 ///
 /// If the expectations in [block] don't match, no error will be raised and no
 /// events will be consumed. If this is used at the end of a test,
 /// [startClosingEventStream] should be called before it.
-Future allowEvents(block()) =>
+Future allowEvents(void Function() block) =>
     _expectOrCollect(mayEmit(_collectStreamMatcher(block)));
 
 /// Returns a StreamMatcher that matches a [WatchEvent] with the given [type]
@@ -146,7 +147,7 @@
     return e is WatchEvent &&
         e.type == type &&
         e.path == p.join(d.sandbox, p.normalize(path));
-  }, "is $type $path");
+  }, 'is $type $path');
 }
 
 /// Returns a [Matcher] that matches a [WatchEvent] for an add event for [path].
@@ -202,8 +203,8 @@
 /// If [contents] is omitted, creates an empty file. If [updateModified] is
 /// `false`, the mock file modification time is not changed.
 void writeFile(String path, {String contents, bool updateModified}) {
-  if (contents == null) contents = "";
-  if (updateModified == null) updateModified = true;
+  contents ??= '';
+  updateModified ??= true;
 
   var fullPath = p.join(d.sandbox, path);
 
@@ -260,9 +261,9 @@
 /// Returns a set of all values returns by [callback].
 ///
 /// [limit] defaults to 3.
-Set<S> withPermutations<S>(S callback(int i, int j, int k), {int limit}) {
-  if (limit == null) limit = 3;
-  var results = Set<S>();
+Set<S> withPermutations<S>(S Function(int, int, int) callback, {int limit}) {
+  limit ??= 3;
+  var results = <S>{};
   for (var i = 0; i < limit; i++) {
     for (var j = 0; j < limit; j++) {
       for (var k = 0; k < limit; k++) {