Fix strong mode warnings and errors.

R=tjblasi@google.com

Review URL: https://codereview.chromium.org//1843173003 .
diff --git a/.analysis_options b/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7563251..5edd140 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.1.2
+
+* Fix all strong mode errors and warnings.
+
 ## 1.1.1
 
 * Fix a bug where listing an absolute glob with `caseInsensitive: false` failed.
diff --git a/lib/src/ast.dart b/lib/src/ast.dart
index 8582d45..5e24e2b 100644
--- a/lib/src/ast.dart
+++ b/lib/src/ast.dart
@@ -20,12 +20,12 @@
   /// Whether this glob could match an absolute path.
   ///
   /// Either this or [canMatchRelative] or both will be true.
-  final bool canMatchAbsolute = false;
+  bool get canMatchAbsolute => false;
 
   /// Whether this glob could match a relative path.
   ///
   /// Either this or [canMatchRelative] or both will be true.
-  final bool canMatchRelative = true;
+  bool get canMatchRelative => true;
 
   AstNode._(this.caseSensitive);
 
@@ -86,14 +86,16 @@
 
     return new OptionsNode(sequences.map((sequence) {
       // Combine any adjacent LiteralNodes in [sequence].
-      return new SequenceNode(sequence.fold([], (combined, node) {
+      return new SequenceNode(sequence.fold/*<List<AstNode>>*/([], (combined, node) {
         if (combined.isEmpty || combined.last is! LiteralNode ||
             node is! LiteralNode) {
           return combined..add(node);
         }
 
         combined[combined.length - 1] = new LiteralNode(
-            combined.last.text + node.text, caseSensitive: caseSensitive);
+            // TODO(nweiz): Avoid casting when sdk#25565 is fixed.
+            (combined.last as LiteralNode).text + (node as LiteralNode).text,
+            caseSensitive: caseSensitive);
         return combined;
       }), caseSensitive: caseSensitive);
     }), caseSensitive: caseSensitive);
@@ -111,10 +113,10 @@
   /// [context] is used to determine what absolute roots look like for this
   /// glob.
   List<SequenceNode> split(p.Context context) {
-    var componentsToReturn = [];
-    var currentComponent;
+    var componentsToReturn = <SequenceNode>[];
+    List<AstNode> currentComponent;
 
-    addNode(node) {
+    addNode(AstNode node) {
       if (currentComponent == null) currentComponent = [];
       currentComponent.add(node);
     }
@@ -127,12 +129,19 @@
     }
 
     for (var node in nodes) {
-      if (node is! LiteralNode || !node.text.contains('/')) {
+      if (node is! LiteralNode) {
         addNode(node);
         continue;
       }
 
-      var text = node.text;
+      // TODO(nweiz): Avoid casting when sdk#25565 is fixed.
+      var literal = node as LiteralNode;
+      if (!literal.text.contains('/')) {
+        addNode(literal);
+        continue;
+      }
+
+      var text = literal.text;
       if (context.style == p.Style.windows) text = text.replaceAll("/", "\\");
       var components = context.split(text);
 
@@ -167,7 +176,7 @@
       // For the final component, only end its sequence (by adding a new empty
       // sequence) if it ends with a separator.
       addNode(new LiteralNode(components.last, caseSensitive: caseSensitive));
-      if (node.text.endsWith('/')) finishComponent();
+      if (literal.text.endsWith('/')) finishComponent();
     }
 
     finishComponent();
diff --git a/lib/src/list_tree.dart b/lib/src/list_tree.dart
index 57ed067..3cce642 100644
--- a/lib/src/list_tree.dart
+++ b/lib/src/list_tree.dart
@@ -5,10 +5,10 @@
 import 'dart:io';
 import 'dart:async';
 
+import 'package:async/async.dart';
 import 'package:path/path.dart' as p;
 
 import 'ast.dart';
-import 'stream_pool.dart';
 import 'utils.dart';
 
 /// The errno for a file or directory not existing on Mac and Linux.
@@ -97,7 +97,7 @@
   }
 
   /// Add the glob represented by [components] to the tree under [root].
-  void _addGlob(String root, List<AstNode> components) {
+  void _addGlob(String root, List<SequenceNode> components) {
     // The first [parent] represents the root directory itself. It may be null
     // here if this is the first option with this particular [root]. If so,
     // we'll create it below.
@@ -170,19 +170,19 @@
   /// List all entities that match this glob beneath [root].
   Stream<FileSystemEntity> list({String root, bool followLinks: true}) {
     if (root == null) root = '.';
-    var pool = new StreamPool();
+    var group = new StreamGroup<FileSystemEntity>();
     for (var rootDir in _trees.keys) {
       var dir = rootDir == '.' ? root : rootDir;
-      pool.add(_trees[rootDir].list(dir, followLinks: followLinks));
+      group.add(_trees[rootDir].list(dir, followLinks: followLinks));
     }
-    pool.closeWhenEmpty();
+    group.close();
 
-    if (!_canOverlap) return pool.stream;
+    if (!_canOverlap) return group.stream;
 
     // TODO(nweiz): Rather than filtering here, avoid double-listing directories
     // in the first place.
     var seen = new Set();
-    return pool.stream.where((entity) {
+    return group.stream.where((entity) {
       if (seen.contains(entity.path)) return false;
       seen.add(entity.path);
       return true;
@@ -193,7 +193,8 @@
   List<FileSystemEntity> listSync({String root, bool followLinks: true}) {
     if (root == null) root = '.';
 
-    var result = _trees.keys.expand((rootDir) {
+    // TODO(nweiz): Remove the explicit annotation when sdk#26139 is fixed.
+    var result = _trees.keys.expand/*<FileSystemEntity>*/((rootDir) {
       var dir = rootDir == '.' ? root : rootDir;
       return _trees[rootDir].listSync(dir, followLinks: followLinks);
     });
@@ -202,7 +203,7 @@
 
     // TODO(nweiz): Rather than filtering here, avoid double-listing directories
     // in the first place.
-    var seen = new Set();
+    var seen = new Set<String>();
     return result.where((entity) {
       if (seen.contains(entity.path)) return false;
       seen.add(entity.path);
@@ -317,21 +318,22 @@
           .where((entity) => _matches(p.relative(entity.path, from: dir)));
     }
 
-    var resultPool = new StreamPool();
+    var resultGroup = new StreamGroup<FileSystemEntity>();
 
     // Don't spawn extra [Directory.list] calls when we already know exactly
     // which subdirectories we're interested in.
     if (_isIntermediate) {
       children.forEach((sequence, child) {
-        resultPool.add(child.list(p.join(dir, sequence.nodes.single.text),
+        resultGroup.add(child.list(
+            p.join(dir, (sequence.nodes.single as LiteralNode).text),
             followLinks: followLinks));
       });
-      resultPool.closeWhenEmpty();
-      return resultPool.stream;
+      resultGroup.close();
+      return resultGroup.stream;
     }
 
-    var resultController = new StreamController(sync: true);
-    resultPool.add(resultController.stream);
+    var resultController = new StreamController<FileSystemEntity>(sync: true);
+    resultGroup.add(resultController.stream);
     new Directory(dir).list(followLinks: followLinks).listen((entity) {
       var basename = p.relative(entity.path, from: dir);
       if (_matches(basename)) resultController.add(entity);
@@ -349,14 +351,16 @@
               (error.osError.errorCode == _ENOENT ||
               error.osError.errorCode == _ENOENT_WIN);
         });
-        resultPool.add(stream);
+        resultGroup.add(stream);
       });
     },
         onError: resultController.addError,
-        onDone: resultController.close);
+        onDone: () {
+          resultController.close();
+          resultGroup.close();
+        });
 
-    resultPool.closeWhenEmpty();
-    return resultPool.stream;
+    return resultGroup.stream;
   }
 
   /// Synchronously lists all entities within [dir] matching this node or its
@@ -376,13 +380,14 @@
     if (_isIntermediate) {
       return children.keys.expand((sequence) {
         return children[sequence].listSync(
-            p.join(dir, sequence.nodes.single.text), followLinks: followLinks);
+            p.join(dir, (sequence.nodes.single as LiteralNode).text),
+            followLinks: followLinks);
       });
     }
 
     return new Directory(dir).listSync(followLinks: followLinks)
         .expand((entity) {
-      var entities = [];
+      var entities = <FileSystemEntity>[];
       var basename = p.relative(entity.path, from: dir);
       if (_matches(basename)) entities.add(entity);
       if (entity is! Directory) return entities;
diff --git a/lib/src/parser.dart b/lib/src/parser.dart
index 14cdc19..d3c7e1d 100644
--- a/lib/src/parser.dart
+++ b/lib/src/parser.dart
@@ -33,7 +33,7 @@
   ///
   /// If [inOptions] is true, this is parsing within an [OptionsNode].
   SequenceNode _parseSequence({bool inOptions: false}) {
-    var nodes = [];
+    var nodes = <AstNode>[];
 
     if (_scanner.isDone) {
       _scanner.error('expected a glob.', position: 0, length: 0);
@@ -99,7 +99,7 @@
           position: _scanner.position - 1);
     }
 
-    var ranges = [];
+    var ranges = <Range>[];
     while (!_scanner.scan(']')) {
       var start = _scanner.position;
       // Allow a backslash to escape a character.
@@ -140,7 +140,7 @@
     if (!_scanner.scan('{')) return null;
     if (_scanner.matches('}')) _scanner.error('unexpected "}".');
 
-    var options = [];
+    var options = <SequenceNode>[];
     do {
       options.add(_parseSequence(inOptions: true));
     } while (_scanner.scan(','));
diff --git a/pubspec.yaml b/pubspec.yaml
index 9c457cf..2845efa 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,9 +1,10 @@
 name: glob
-version: 1.1.1
+version: 1.1.2
 author: "Dart Team <misc@dartlang.org>"
 homepage: https://github.com/dart-lang/glob
 description: Bash-style filename globbing.
 dependencies:
+  async: "^1.2.0"
   collection: ">=1.1.0 <2.0.0"
   path: ">=1.3.0 <2.0.0"
   string_scanner: ">=0.1.0 <0.2.0"