Test on oldest supported SDK, enable and fix many lints
diff --git a/.travis.yml b/.travis.yml
index 9d8258c..cae5503 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,16 +1,13 @@
 language: dart
 
-# By default, builds are run in containers.
-# https://docs.travis-ci.com/user/getting-started/#Selecting-infrastructure-(optional)
-# Set `sudo: true` to disable containers if you need to use sudo in your scripts.
-# sudo: true
-
 dart:
+- 2.0.0
 - dev
-# See https://docs.travis-ci.com/user/languages/dart/ for details.
+
 dart_task:
   - dartfmt
   - dartanalyzer
+
   # TODO: reinstate tests once https://github.com/dart-lang/http_retry/issues/6 is fixed
   #  - test: --platform vm
   #    xvfb: false
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..815f325
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,99 @@
+include: package:pedantic/analysis_options.yaml
+analyzer:
+  strong-mode:
+    implicit-casts: false
+  errors:
+    dead_code: error
+    override_on_non_overriding_method: error
+    unused_element: error
+    unused_import: error
+    unused_local_variable: error
+linter:
+  rules:
+    - always_declare_return_types
+    - annotate_overrides
+    - avoid_bool_literals_in_conditional_expressions
+    - avoid_classes_with_only_static_members
+    - avoid_empty_else
+    - avoid_function_literals_in_foreach_calls
+    - avoid_init_to_null
+    - avoid_null_checks_in_equality_operators
+    - avoid_relative_lib_imports
+    - avoid_renaming_method_parameters
+    - avoid_return_types_on_setters
+    - avoid_returning_null
+    - avoid_returning_null_for_future
+    - avoid_returning_null_for_void
+    - avoid_returning_this
+    - avoid_shadowing_type_parameters
+    - avoid_single_cascade_in_expression_statements
+    - avoid_types_as_parameter_names
+    - avoid_unused_constructor_parameters
+    - await_only_futures
+    - camel_case_types
+    - cancel_subscriptions
+    #- cascade_invocations
+    - comment_references
+    - constant_identifier_names
+    - control_flow_in_finally
+    - directives_ordering
+    - empty_catches
+    - empty_constructor_bodies
+    - empty_statements
+    - file_names
+    - hash_and_equals
+    - implementation_imports
+    - invariant_booleans
+    - iterable_contains_unrelated_type
+    - join_return_with_assignment
+    - library_names
+    - library_prefixes
+    - list_remove_unrelated_type
+    - literal_only_boolean_expressions
+    - no_adjacent_strings_in_list
+    - no_duplicate_case_values
+    - non_constant_identifier_names
+    - null_closures
+    - omit_local_variable_types
+    - only_throw_errors
+    - overridden_fields
+    - package_api_docs
+    - package_names
+    - package_prefixed_library_names
+    - prefer_adjacent_string_concatenation
+    - prefer_collection_literals
+    - prefer_conditional_assignment
+    - prefer_const_constructors
+    - prefer_contains
+    - prefer_equal_for_default_values
+    - prefer_final_fields
+    #- prefer_final_locals
+    - prefer_generic_function_type_aliases
+    - prefer_initializing_formals
+    - prefer_interpolation_to_compose_strings
+    - prefer_is_empty
+    - prefer_is_not_empty
+    - prefer_null_aware_operators
+    #- prefer_single_quotes
+    - prefer_typing_uninitialized_variables
+    - recursive_getters
+    - slash_for_doc_comments
+    - test_types_in_equals
+    - throw_in_finally
+    - type_init_formals
+    - unawaited_futures
+    - unnecessary_await_in_return
+    - unnecessary_brace_in_string_interps
+    - unnecessary_const
+    - unnecessary_getters_setters
+    - unnecessary_lambdas
+    - unnecessary_new
+    - unnecessary_null_aware_assignments
+    - unnecessary_parenthesis
+    - unnecessary_statements
+    - unnecessary_this
+    - unrelated_type_equality_checks
+    #- use_function_type_syntax_for_parameters
+    - use_rethrow_when_possible
+    - valid_regexps
+    - void_checks
diff --git a/lib/http_retry.dart b/lib/http_retry.dart
index e1b08fd..5bb3695 100644
--- a/lib/http_retry.dart
+++ b/lib/http_retry.dart
@@ -7,6 +7,7 @@
 
 import 'package:async/async.dart';
 import 'package:http/http.dart';
+import 'package:pedantic/pedantic.dart';
 
 /// An HTTP client wrapper that automatically retries failing requests.
 class RetryClient extends BaseClient {
@@ -28,7 +29,7 @@
   /// The callback to call to indicate that a request is being retried.
   final void Function(BaseRequest, BaseResponse, int) _onRetry;
 
-  /// Creates a client wrapping [inner] that retries HTTP requests.
+  /// Creates a client wrapping [_inner] that retries HTTP requests.
   ///
   /// This retries a failing request [retries] times (3 by default). Note that
   /// `n` retries means that the request will be sent at most `n + 1` times.
@@ -58,7 +59,7 @@
         _whenError = whenError ?? ((_, __) => false),
         _delay = delay ??
             ((retryCount) =>
-                new Duration(milliseconds: 500) * math.pow(1.5, retryCount)),
+                Duration(milliseconds: 500) * math.pow(1.5, retryCount)),
         _onRetry = onRetry {
     RangeError.checkNotNegative(_retries, "retries");
   }
@@ -87,11 +88,12 @@
             whenError: whenError,
             onRetry: onRetry);
 
+  @override
   Future<StreamedResponse> send(BaseRequest request) async {
-    var splitter = new StreamSplitter(request.finalize());
+    var splitter = StreamSplitter(request.finalize());
 
     var i = 0;
-    while (true) {
+    for (;;) {
       StreamedResponse response;
       try {
         response = await _inner.send(_copyRequest(request, splitter.split()));
@@ -104,10 +106,10 @@
 
         // Make sure the response stream is listened to so that we don't leave
         // dangling connections.
-        response.stream.listen((_) {}).cancel()?.catchError((_) {});
+        unawaited(response.stream.listen((_) {}).cancel()?.catchError((_) {}));
       }
 
-      await new Future.delayed(_delay(i));
+      await Future.delayed(_delay(i));
       if (_onRetry != null) _onRetry(request, response, i);
       i++;
     }
@@ -115,7 +117,7 @@
 
   /// Returns a copy of [original] with the given [body].
   StreamedRequest _copyRequest(BaseRequest original, Stream<List<int>> body) {
-    var request = new StreamedRequest(original.method, original.url);
+    var request = StreamedRequest(original.method, original.url);
     request.contentLength = original.contentLength;
     request.followRedirects = original.followRedirects;
     request.headers.addAll(original.headers);
@@ -130,5 +132,6 @@
     return request;
   }
 
+  @override
   void close() => _inner.close();
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 74168c4..85743ad 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -11,6 +11,7 @@
 dependencies:
   async: ^2.0.7
   http: '>=0.11.0 <0.13.0'
+  pedantic: ^1.0.0
 
 dev_dependencies:
   fake_async: ^1.0.0
diff --git a/test/http_retry_test.dart b/test/http_retry_test.dart
index dc7bc19..b51ed1f 100644
--- a/test/http_retry_test.dart
+++ b/test/http_retry_test.dart
@@ -5,32 +5,29 @@
 import 'package:fake_async/fake_async.dart';
 import 'package:http/http.dart';
 import 'package:http/testing.dart';
-import 'package:test/test.dart';
-
 import 'package:http_retry/http_retry.dart';
+import 'package:test/test.dart';
 
 void main() {
   group("doesn't retry when", () {
     test("a request has a non-503 error code", () async {
-      var client = new RetryClient(new MockClient(
-          expectAsync1((_) async => new Response("", 502), count: 1)));
+      var client = RetryClient(
+          MockClient(expectAsync1((_) async => Response("", 502), count: 1)));
       var response = await client.get("http://example.org");
       expect(response.statusCode, equals(502));
     });
 
     test("a request doesn't match when()", () async {
-      var client = new RetryClient(
-          new MockClient(
-              expectAsync1((_) async => new Response("", 503), count: 1)),
+      var client = RetryClient(
+          MockClient(expectAsync1((_) async => Response("", 503), count: 1)),
           when: (_) => false);
       var response = await client.get("http://example.org");
       expect(response.statusCode, equals(503));
     });
 
     test("retries is 0", () async {
-      var client = new RetryClient(
-          new MockClient(
-              expectAsync1((_) async => new Response("", 503), count: 1)),
+      var client = RetryClient(
+          MockClient(expectAsync1((_) async => Response("", 503), count: 1)),
           retries: 0);
       var response = await client.get("http://example.org");
       expect(response.statusCode, equals(503));
@@ -39,10 +36,10 @@
 
   test("retries on a 503 by default", () async {
     var count = 0;
-    var client = new RetryClient(
-        new MockClient(expectAsync1((request) async {
+    var client = RetryClient(
+        MockClient(expectAsync1((request) async {
           count++;
-          return count < 2 ? new Response("", 503) : new Response("", 200);
+          return count < 2 ? Response("", 503) : Response("", 200);
         }, count: 2)),
         delay: (_) => Duration.zero);
 
@@ -52,10 +49,10 @@
 
   test("retries on any request where when() returns true", () async {
     var count = 0;
-    var client = new RetryClient(
-        new MockClient(expectAsync1((request) async {
+    var client = RetryClient(
+        MockClient(expectAsync1((request) async {
           count++;
-          return new Response("", 503,
+          return Response("", 503,
               headers: {"retry": count < 2 ? "true" : "false"});
         }, count: 2)),
         when: (response) => response.headers["retry"] == "true",
@@ -68,13 +65,14 @@
 
   test("retries on any request where whenError() returns true", () async {
     var count = 0;
-    var client = new RetryClient(
-        new MockClient(expectAsync1((request) async {
+    var client = RetryClient(
+        MockClient(expectAsync1((request) async {
           count++;
-          if (count < 2) throw "oh no";
-          return new Response("", 200);
+          if (count < 2) throw StateError("oh no");
+          return Response("", 200);
         }, count: 2)),
-        whenError: (error, _) => error == "oh no",
+        whenError: (error, _) =>
+            error is StateError && error.message == "oh no",
         delay: (_) => Duration.zero);
 
     var response = await client.get("http://example.org");
@@ -82,27 +80,26 @@
   });
 
   test("doesn't retry a request where whenError() returns false", () async {
-    var client = new RetryClient(
-        new MockClient(expectAsync1((request) async => throw "oh no")),
+    var client = RetryClient(
+        MockClient(expectAsync1((request) async => throw StateError("oh no"))),
         whenError: (error, _) => error == "oh yeah",
         delay: (_) => Duration.zero);
 
-    expect(client.get("http://example.org"), throwsA("oh no"));
+    expect(client.get("http://example.org"),
+        throwsA(isStateError.having((e) => e.message, 'message', "oh no")));
   });
 
   test("retries three times by default", () async {
-    var client = new RetryClient(
-        new MockClient(
-            expectAsync1((_) async => new Response("", 503), count: 4)),
+    var client = RetryClient(
+        MockClient(expectAsync1((_) async => Response("", 503), count: 4)),
         delay: (_) => Duration.zero);
     var response = await client.get("http://example.org");
     expect(response.statusCode, equals(503));
   });
 
   test("retries the given number of times", () async {
-    var client = new RetryClient(
-        new MockClient(
-            expectAsync1((_) async => new Response("", 503), count: 13)),
+    var client = RetryClient(
+        MockClient(expectAsync1((_) async => Response("", 503), count: 13)),
         retries: 12,
         delay: (_) => Duration.zero);
     var response = await client.get("http://example.org");
@@ -110,87 +107,82 @@
   });
 
   test("waits 1.5x as long each time by default", () {
-    new FakeAsync().run((fake) {
+    FakeAsync().run((fake) {
       var count = 0;
-      var client = new RetryClient(new MockClient(expectAsync1((_) async {
+      var client = RetryClient(MockClient(expectAsync1((_) async {
         count++;
         if (count == 1) {
           expect(fake.elapsed, equals(Duration.zero));
         } else if (count == 2) {
-          expect(fake.elapsed, equals(new Duration(milliseconds: 500)));
+          expect(fake.elapsed, equals(Duration(milliseconds: 500)));
         } else if (count == 3) {
-          expect(fake.elapsed, equals(new Duration(milliseconds: 1250)));
+          expect(fake.elapsed, equals(Duration(milliseconds: 1250)));
         } else if (count == 4) {
-          expect(fake.elapsed, equals(new Duration(milliseconds: 2375)));
+          expect(fake.elapsed, equals(Duration(milliseconds: 2375)));
         }
 
-        return new Response("", 503);
+        return Response("", 503);
       }, count: 4)));
 
       expect(client.get("http://example.org"), completes);
-      fake.elapse(new Duration(minutes: 10));
+      fake.elapse(Duration(minutes: 10));
     });
   });
 
   test("waits according to the delay parameter", () {
-    new FakeAsync().run((fake) {
+    FakeAsync().run((fake) {
       var count = 0;
-      var client = new RetryClient(
-          new MockClient(expectAsync1((_) async {
+      var client = RetryClient(
+          MockClient(expectAsync1((_) async {
             count++;
             if (count == 1) {
               expect(fake.elapsed, equals(Duration.zero));
             } else if (count == 2) {
               expect(fake.elapsed, equals(Duration.zero));
             } else if (count == 3) {
-              expect(fake.elapsed, equals(new Duration(seconds: 1)));
+              expect(fake.elapsed, equals(Duration(seconds: 1)));
             } else if (count == 4) {
-              expect(fake.elapsed, equals(new Duration(seconds: 3)));
+              expect(fake.elapsed, equals(Duration(seconds: 3)));
             }
 
-            return new Response("", 503);
+            return Response("", 503);
           }, count: 4)),
-          delay: (requestCount) => new Duration(seconds: requestCount));
+          delay: (requestCount) => Duration(seconds: requestCount));
 
       expect(client.get("http://example.org"), completes);
-      fake.elapse(new Duration(minutes: 10));
+      fake.elapse(Duration(minutes: 10));
     });
   });
 
   test("waits according to the delay list", () {
-    new FakeAsync().run((fake) {
+    FakeAsync().run((fake) {
       var count = 0;
-      var client = new RetryClient.withDelays(
-          new MockClient(expectAsync1((_) async {
+      var client = RetryClient.withDelays(
+          MockClient(expectAsync1((_) async {
             count++;
             if (count == 1) {
               expect(fake.elapsed, equals(Duration.zero));
             } else if (count == 2) {
-              expect(fake.elapsed, equals(new Duration(seconds: 1)));
+              expect(fake.elapsed, equals(Duration(seconds: 1)));
             } else if (count == 3) {
-              expect(fake.elapsed, equals(new Duration(seconds: 61)));
+              expect(fake.elapsed, equals(Duration(seconds: 61)));
             } else if (count == 4) {
-              expect(fake.elapsed, equals(new Duration(seconds: 73)));
+              expect(fake.elapsed, equals(Duration(seconds: 73)));
             }
 
-            return new Response("", 503);
+            return Response("", 503);
           }, count: 4)),
-          [
-            new Duration(seconds: 1),
-            new Duration(minutes: 1),
-            new Duration(seconds: 12)
-          ]);
+          [Duration(seconds: 1), Duration(minutes: 1), Duration(seconds: 12)]);
 
       expect(client.get("http://example.org"), completes);
-      fake.elapse(new Duration(minutes: 10));
+      fake.elapse(Duration(minutes: 10));
     });
   });
 
   test("calls onRetry for each retry", () async {
     var count = 0;
-    var client = new RetryClient(
-        new MockClient(
-            expectAsync1((_) async => new Response("", 503), count: 3)),
+    var client = RetryClient(
+        MockClient(expectAsync1((_) async => Response("", 503), count: 3)),
         retries: 2,
         delay: (_) => Duration.zero,
         onRetry: expectAsync3((request, response, retryCount) {
@@ -204,8 +196,8 @@
   });
 
   test("copies all request attributes for each attempt", () async {
-    var client = new RetryClient.withDelays(
-        new MockClient(expectAsync1((request) async {
+    var client = RetryClient.withDelays(
+        MockClient(expectAsync1((request) async {
           expect(request.contentLength, equals(5));
           expect(request.followRedirects, isFalse);
           expect(request.headers, containsPair("foo", "bar"));
@@ -214,11 +206,11 @@
           expect(request.persistentConnection, isFalse);
           expect(request.url, equals(Uri.parse("http://example.org")));
           expect(request.body, equals("hello"));
-          return new Response("", 503);
+          return Response("", 503);
         }, count: 2)),
         [Duration.zero]);
 
-    var request = new Request("POST", Uri.parse("http://example.org"));
+    var request = Request("POST", Uri.parse("http://example.org"));
     request.body = "hello";
     request.followRedirects = false;
     request.headers["foo"] = "bar";