Skip to content

Commit 1a52033

Browse files
authored
Add some stricter analysis (flutter#64)
- Enable errors that would fail internally - Add `comment_references` lint - this makes DartDocs output more usable and there isn't any reason to have unclickable references. - Add `prefer_typing_uninitialized_variables` lint - this prevents some unintentionally dynamic behavior. - Disable implicit casts. - Use function type syntax for the ManuallyClosedWatcher factory. - Remove some unused utilities.
1 parent 539ed40 commit 1a52033

13 files changed

+137
-179
lines changed

analysis_options.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
analyzer:
2+
strong-mode:
3+
implicit-casts: false
4+
errors:
5+
todo: ignore
6+
unused_import: error
7+
unused_element: error
8+
unused_local_variable: error
9+
dead_code: error
10+
11+
linter:
12+
rules:
13+
- comment_references
14+
- prefer_typing_uninitialized_variables

benchmark/path_set.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ abstract class PathSetBenchmark extends BenchmarkBase {
3131
/// Each virtual directory contains ten entries: either subdirectories or
3232
/// files.
3333
void walkTree(int depth, callback(String path)) {
34-
recurse(path, remainingDepth) {
34+
recurse(String path, remainingDepth) {
3535
for (var i = 0; i < 10; i++) {
3636
var padded = i.toString().padLeft(2, '0');
3737
if (remainingDepth == 0) {

lib/src/directory_watcher/linux.dart

+7-5
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,14 @@ class _LinuxDirectoryWatcher
7979
.transform(new BatchedStreamTransformer<FileSystemEvent>());
8080
_listen(innerStream, _onBatch, onError: _eventsController.addError);
8181

82-
_listen(new Directory(path).list(recursive: true), (entity) {
82+
_listen(new Directory(path).list(recursive: true),
83+
(FileSystemEntity entity) {
8384
if (entity is Directory) {
8485
_watchSubdir(entity.path);
8586
} else {
8687
_files.add(entity.path);
8788
}
88-
}, onError: (error, stackTrace) {
89+
}, onError: (error, StackTrace stackTrace) {
8990
_eventsController.addError(error, stackTrace);
9091
close();
9192
}, onDone: () {
@@ -207,14 +208,15 @@ class _LinuxDirectoryWatcher
207208

208209
/// Emits [ChangeType.ADD] events for the recursive contents of [path].
209210
void _addSubdir(String path) {
210-
_listen(new Directory(path).list(recursive: true), (entity) {
211+
_listen(new Directory(path).list(recursive: true),
212+
(FileSystemEntity entity) {
211213
if (entity is Directory) {
212214
_watchSubdir(entity.path);
213215
} else {
214216
_files.add(entity.path);
215217
_emit(ChangeType.ADD, entity.path);
216218
}
217-
}, onError: (error, stackTrace) {
219+
}, onError: (error, StackTrace stackTrace) {
218220
// Ignore an exception caused by the dir not existing. It's fine if it
219221
// was added and then quickly removed.
220222
if (error is FileSystemException) return;
@@ -252,7 +254,7 @@ class _LinuxDirectoryWatcher
252254
/// [_subscriptions] so that it can be canceled when [close] is called.
253255
void _listen<T>(Stream<T> stream, void onData(T event),
254256
{Function onError, void onDone(), bool cancelOnError}) {
255-
var subscription;
257+
StreamSubscription subscription;
256258
subscription = stream.listen(onData, onError: onError, onDone: () {
257259
_subscriptions.remove(subscription);
258260
if (onDone != null) onDone();

lib/src/directory_watcher/mac_os.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ class _MacOSDirectoryWatcher
5454

5555
/// The subscription to the stream returned by [Directory.watch].
5656
///
57-
/// This is separate from [_subscriptions] because this stream occasionally
58-
/// needs to be resubscribed in order to work around issue 14849.
57+
/// This is separate from [_listSubscriptions] because this stream
58+
/// occasionally needs to be resubscribed in order to work around issue 14849.
5959
StreamSubscription<List<FileSystemEvent>> _watchSubscription;
6060

6161
/// The subscription to the [Directory.list] call for the initial listing of
@@ -143,7 +143,7 @@ class _MacOSDirectoryWatcher
143143

144144
_emitEvent(ChangeType.ADD, entity.path);
145145
_files.add(entity.path);
146-
}, onError: (e, stackTrace) {
146+
}, onError: (e, StackTrace stackTrace) {
147147
_emitError(e, stackTrace);
148148
}, onDone: () {
149149
_listSubscriptions.remove(subscription);
@@ -212,7 +212,7 @@ class _MacOSDirectoryWatcher
212212
/// one exists.
213213
///
214214
/// If [batch] doesn't contain any contradictory events (e.g. DELETE and
215-
/// CREATE, or events with different values for [isDirectory]), this returns a
215+
/// CREATE, or events with different values for `isDirectory`), this returns a
216216
/// single event that describes what happened to the path in question.
217217
///
218218
/// If [batch] does contain contradictory events, this returns `null` to

lib/src/directory_watcher/polling.dart

+6-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class PollingDirectoryWatcher extends ResubscribableWatcher
1919

2020
/// Creates a new polling watcher monitoring [directory].
2121
///
22-
/// If [_pollingDelay] is passed, it specifies the amount of time the watcher
22+
/// If [pollingDelay] is passed, it specifies the amount of time the watcher
2323
/// will pause between successive polls of the directory contents. Making this
2424
/// shorter will give more immediate feedback at the expense of doing more IO
2525
/// and higher CPU usage. Defaults to one second.
@@ -68,13 +68,13 @@ class _PollingDirectoryWatcher
6868

6969
/// The set of files that have been seen in the current directory listing.
7070
///
71-
/// Used to tell which files have been removed: files that are in [_statuses]
72-
/// but not in here when a poll completes have been removed.
71+
/// Used to tell which files have been removed: files that are in
72+
/// [_lastModifieds] but not in here when a poll completes have been removed.
7373
final _polledFiles = new Set<String>();
7474

7575
_PollingDirectoryWatcher(this.path, this._pollingDelay) {
76-
_filesToProcess =
77-
new AsyncQueue<String>(_processFile, onError: (e, stackTrace) {
76+
_filesToProcess = new AsyncQueue<String>(_processFile,
77+
onError: (e, StackTrace stackTrace) {
7878
if (!_events.isClosed) _events.addError(e, stackTrace);
7979
});
8080

@@ -113,7 +113,7 @@ class _PollingDirectoryWatcher
113113

114114
if (entity is! File) return;
115115
_filesToProcess.add(entity.path);
116-
}, onError: (error, stackTrace) {
116+
}, onError: (error, StackTrace stackTrace) {
117117
if (!isDirectoryNotFoundException(error)) {
118118
// It's some unknown error. Pipe it over to the event stream so the
119119
// user can see it.

lib/src/directory_watcher/windows.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ class _WindowsDirectoryWatcher
188188
_files.add(entity.path);
189189
}, onDone: () {
190190
_listSubscriptions.remove(subscription);
191-
}, onError: (e, stackTrace) {
191+
}, onError: (e, StackTrace stackTrace) {
192192
_listSubscriptions.remove(subscription);
193193
_emitError(e, stackTrace);
194194
}, cancelOnError: true);
@@ -253,7 +253,7 @@ class _WindowsDirectoryWatcher
253253
/// one exists.
254254
///
255255
/// If [batch] doesn't contain any contradictory events (e.g. DELETE and
256-
/// CREATE, or events with different values for [isDirectory]), this returns a
256+
/// CREATE, or events with different values for `isDirectory`), this returns a
257257
/// single event that describes what happened to the path in question.
258258
///
259259
/// If [batch] does contain contradictory events, this returns `null` to
@@ -382,7 +382,7 @@ class _WindowsDirectoryWatcher
382382
_files.clear();
383383
var completer = new Completer();
384384
var stream = new Directory(path).list(recursive: true);
385-
void handleEntity(entity) {
385+
void handleEntity(FileSystemEntity entity) {
386386
if (entity is! Directory) _files.add(entity.path);
387387
}
388388

lib/src/file_watcher.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import 'file_watcher/polling.dart';
1515
/// it will emit a single [ChangeType.REMOVE] event and then close the stream.
1616
///
1717
/// If the file is deleted and quickly replaced (when a new file is moved in its
18-
/// place, for example) this will emit a [ChangeTime.MODIFY] event.
18+
/// place, for example) this will emit a [ChangeType.MODIFY] event.
1919
abstract class FileWatcher implements Watcher {
2020
/// Creates a new [FileWatcher] monitoring [file].
2121
///

lib/src/file_watcher/polling.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class _PollingFileWatcher implements FileWatcher, ManuallyClosedWatcher {
5858
return;
5959
}
6060

61-
var modified;
61+
DateTime modified;
6262
try {
6363
try {
6464
modified = await getModificationTime(path);

lib/src/path_set.dart

+8-8
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ class PathSet {
4949
/// empty set.
5050
Set<String> remove(String path) {
5151
path = _normalize(path);
52-
var parts = new Queue.from(p.split(path));
52+
var parts = new Queue.of(p.split(path));
5353

5454
// Remove the children of [dir], as well as [dir] itself if necessary.
5555
//
5656
// [partialPath] is the path to [dir], and a prefix of [path]; the remaining
5757
// components of [path] are in [parts].
58-
Set<String> recurse(dir, partialPath) {
58+
Set<String> recurse(_Entry dir, String partialPath) {
5959
if (parts.length > 1) {
6060
// If there's more than one component left in [path], recurse down to
6161
// the next level.
@@ -97,7 +97,7 @@ class PathSet {
9797
/// [dirPath] should be the path to [dir].
9898
Set<String> _explicitPathsWithin(_Entry dir, String dirPath) {
9999
var paths = new Set<String>();
100-
recurse(dir, path) {
100+
recurse(_Entry dir, String path) {
101101
dir.contents.forEach((name, entry) {
102102
var entryPath = p.join(path, name);
103103
if (entry.isExplicit) paths.add(p.join(root, entryPath));
@@ -110,9 +110,9 @@ class PathSet {
110110
return paths;
111111
}
112112

113-
/// Returns whether [this] contains [path].
113+
/// Returns whether this set contains [path].
114114
///
115-
/// This only returns true for paths explicitly added to [this].
115+
/// This only returns true for paths explicitly added to this set.
116116
/// Implicitly-added directories can be inspected using [containsDir].
117117
bool contains(String path) {
118118
path = _normalize(path);
@@ -126,7 +126,7 @@ class PathSet {
126126
return entry.isExplicit;
127127
}
128128

129-
/// Returns whether [this] contains paths beneath [path].
129+
/// Returns whether this set contains paths beneath [path].
130130
bool containsDir(String path) {
131131
path = _normalize(path);
132132
var entry = _entries;
@@ -143,7 +143,7 @@ class PathSet {
143143
List<String> get paths {
144144
var result = <String>[];
145145

146-
recurse(dir, path) {
146+
recurse(_Entry dir, String path) {
147147
for (var name in dir.contents.keys) {
148148
var entry = dir.contents[name];
149149
var entryPath = p.join(path, name);
@@ -156,7 +156,7 @@ class PathSet {
156156
return result;
157157
}
158158

159-
/// Removes all paths from [this].
159+
/// Removes all paths from this set.
160160
void clear() {
161161
_entries.contents.clear();
162162
}

lib/src/resubscribable.dart

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import 'dart:async';
77
import '../watcher.dart';
88
import 'watch_event.dart';
99

10-
typedef ManuallyClosedWatcher WatcherFactory();
11-
1210
/// A wrapper for [ManuallyClosedWatcher] that encapsulates support for closing
1311
/// the watcher when it has no subscribers and re-opening it when it's
1412
/// re-subscribed.
@@ -24,7 +22,7 @@ typedef ManuallyClosedWatcher WatcherFactory();
2422
/// takes a factory function that produces instances of the inner class.
2523
abstract class ResubscribableWatcher implements Watcher {
2624
/// The factory function that produces instances of the inner class.
27-
final WatcherFactory _factory;
25+
final ManuallyClosedWatcher Function() _factory;
2826

2927
final String path;
3028

@@ -39,8 +37,8 @@ abstract class ResubscribableWatcher implements Watcher {
3937
/// Creates a new [ResubscribableWatcher] wrapping the watchers
4038
/// emitted by [_factory].
4139
ResubscribableWatcher(this.path, this._factory) {
42-
var watcher;
43-
var subscription;
40+
ManuallyClosedWatcher watcher;
41+
StreamSubscription subscription;
4442

4543
_eventsController = new StreamController<WatchEvent>.broadcast(
4644
onListen: () {

lib/src/utils.dart

-51
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import 'dart:async';
66
import 'dart:io';
77
import 'dart:collection';
88

9-
import 'package:async/async.dart';
10-
119
/// Returns `true` if [error] is a [FileSystemException] for a missing
1210
/// directory.
1311
bool isDirectoryNotFoundException(error) {
@@ -22,55 +20,6 @@ bool isDirectoryNotFoundException(error) {
2220
Set<T> unionAll<T>(Iterable<Set<T>> sets) =>
2321
sets.fold(new Set<T>(), (union, set) => union.union(set));
2422

25-
/// Returns a buffered stream that will emit the same values as the stream
26-
/// returned by [future] once [future] completes.
27-
///
28-
/// If [future] completes to an error, the return value will emit that error and
29-
/// then close.
30-
///
31-
/// If [broadcast] is true, a broadcast stream is returned. This assumes that
32-
/// the stream returned by [future] will be a broadcast stream as well.
33-
/// [broadcast] defaults to false.
34-
Stream<T> futureStream<T>(Future<Stream<T>> future, {bool broadcast: false}) {
35-
var subscription;
36-
StreamController<T> controller;
37-
38-
future = DelegatingFuture.typed(future.catchError((e, stackTrace) {
39-
// Since [controller] is synchronous, it's likely that emitting an error
40-
// will cause it to be cancelled before we call close.
41-
if (controller != null) controller.addError(e, stackTrace);
42-
if (controller != null) controller.close();
43-
controller = null;
44-
}));
45-
46-
onListen() {
47-
future.then((stream) {
48-
if (controller == null) return;
49-
subscription = stream.listen(controller.add,
50-
onError: controller.addError, onDone: controller.close);
51-
});
52-
}
53-
54-
onCancel() {
55-
if (subscription != null) subscription.cancel();
56-
subscription = null;
57-
controller = null;
58-
}
59-
60-
if (broadcast) {
61-
controller = new StreamController.broadcast(
62-
sync: true, onListen: onListen, onCancel: onCancel);
63-
} else {
64-
controller = new StreamController(
65-
sync: true, onListen: onListen, onCancel: onCancel);
66-
}
67-
return controller.stream;
68-
}
69-
70-
/// Like [new Future], but avoids around issue 11911 by using [new Future.value]
71-
/// under the covers.
72-
Future newFuture(callback()) => new Future.value().then((_) => callback());
73-
7423
/// A stream transformer that batches all events that are sent at the same time.
7524
///
7625
/// When multiple events are synchronously added to a stream controller, the

0 commit comments

Comments
 (0)