Move to setup-dart for CI

Also enable and fix some good lints
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 2ac7525..71fdee6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -1,32 +1,51 @@
-name: Dart
+name: CI
 
 on:
-  pull_request:
+  # Run on PRs and pushes to the default branch.
   push:
-    branches:
-      - master
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
   schedule:
-    # “At 00:00 (UTC) on Sunday.”
-    - cron: '0 0 * * 0'
+    - cron: "0 0 * * 0"
+
+env:
+  PUB_ENVIRONMENT: bot.github
 
 jobs:
-  build:
+  # Check code formatting and static analysis on a single OS (linux)
+  # against Dart dev and stable.
+  analyze:
     runs-on: ubuntu-latest
-
-    container:
-      image:  google/dart:beta
-
+    strategy:
+      matrix:
+        sdk: [dev]
     steps:
       - uses: actions/checkout@v2
+      - uses: dart-lang/setup-dart@v1.1
+        with:
+          sdk: ${{ matrix.sdk }}
+      - id: install
+        run: dart pub get
+      - run: dart format --output=none --set-exit-if-changed .
+        if: always() && steps.install.outcome == 'success'
+      - run: dart analyze --fatal-infos
+        if: always() && steps.install.outcome == 'success'
 
-      - name: pub get
-        run: pub get
-
-      - name: dart format
-        run: dart format --output=none --set-exit-if-changed .
-
-      - name: dart analyze
-        run: dart analyze
-
-      - name: dart test
-        run: dart test
+  test:
+    needs: analyze
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [ubuntu-latest]
+        sdk: [2.12.0, dev]
+    steps:
+      - uses: actions/checkout@v2
+      - uses: dart-lang/setup-dart@v1.1
+        with:
+          sdk: ${{ matrix.sdk }}
+      - id: install
+        run: dart pub get
+      - run: dart test --platform vm
+        if: always() && steps.install.outcome == 'success'
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 180004e..adb30b1 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,7 +1,15 @@
+include: package:lints/recommended.yaml
+
 analyzer:
+  strong-mode:
+    implicit-casts: false
 
 linter:
   rules:
     - always_declare_return_types
     - directives_ordering
+    - lines_longer_than_80_chars
     - public_member_api_docs
+    - slash_for_doc_comments
+    - unnecessary_const
+    - unnecessary_new
diff --git a/lib/test_reflective_loader.dart b/lib/test_reflective_loader.dart
index 3528a43..db87681 100644
--- a/lib/test_reflective_loader.dart
+++ b/lib/test_reflective_loader.dart
@@ -9,40 +9,29 @@
 
 import 'package:test/test.dart' as test_package;
 
-/**
- * A marker annotation used to annotate test methods which are expected to fail
- * when asserts are enabled.
- */
-const _AssertFailingTest assertFailingTest = const _AssertFailingTest();
+/// A marker annotation used to annotate test methods which are expected to fail
+/// when asserts are enabled.
+const _AssertFailingTest assertFailingTest = _AssertFailingTest();
 
-/**
- * A marker annotation used to annotate test methods which are expected to fail.
- */
-const FailingTest failingTest = const FailingTest();
+/// A marker annotation used to annotate test methods which are expected to
+/// fail.
+const FailingTest failingTest = FailingTest();
 
-/**
- * A marker annotation used to instruct dart2js to keep reflection information
- * for the annotated classes.
- */
-const _ReflectiveTest reflectiveTest = const _ReflectiveTest();
+/// A marker annotation used to instruct dart2js to keep reflection information
+/// for the annotated classes.
+const _ReflectiveTest reflectiveTest = _ReflectiveTest();
 
-/**
- * A marker annotation used to annotate test methods that should be skipped.
- */
-const SkippedTest skippedTest = const SkippedTest();
+/// A marker annotation used to annotate test methods that should be skipped.
+const SkippedTest skippedTest = SkippedTest();
 
-/**
- * A marker annotation used to annotate "solo" groups and tests.
- */
-const _SoloTest soloTest = const _SoloTest();
+/// A marker annotation used to annotate "solo" groups and tests.
+const _SoloTest soloTest = _SoloTest();
 
 final List<_Group> _currentGroups = <_Group>[];
 int _currentSuiteLevel = 0;
 String _currentSuiteName = '';
 
-/**
- * Is `true` the application is running in the checked mode.
- */
+/// Is `true` the application is running in the checked mode.
 final bool _isCheckedMode = () {
   try {
     assert(false);
@@ -52,13 +41,11 @@
   }
 }();
 
-/**
- * Run the [define] function parameter that calls [defineReflectiveTests] to
- * add normal and "solo" tests, and also calls [defineReflectiveSuite] to
- * create embedded suites.  If the current suite is the top-level one, perform
- * check for "solo" groups and tests, and run all or only "solo" items.
- */
-void defineReflectiveSuite(void define(), {String name = ''}) {
+/// Run the [define] function parameter that calls [defineReflectiveTests] to
+/// add normal and "solo" tests, and also calls [defineReflectiveSuite] to
+/// create embedded suites.  If the current suite is the top-level one, perform
+/// check for "solo" groups and tests, and run all or only "solo" items.
+void defineReflectiveSuite(void Function() define, {String name = ''}) {
   String groupName = _currentSuiteName;
   _currentSuiteLevel++;
   try {
@@ -71,32 +58,30 @@
   _addTestsIfTopLevelSuite();
 }
 
-/**
- * Runs test methods existing in the given [type].
- *
- * If there is a "solo" test method in the top-level suite, only "solo" methods
- * are run.
- *
- * If there is a "solo" test type, only its test methods are run.
- *
- * Otherwise all tests methods of all test types are run.
- *
- * Each method is run with a new instance of [type].
- * So, [type] should have a default constructor.
- *
- * If [type] declares method `setUp`, it methods will be invoked before any test
- * method invocation.
- *
- * If [type] declares method `tearDown`, it will be invoked after any test
- * method invocation. If method returns [Future] to test some asynchronous
- * behavior, then `tearDown` will be invoked in `Future.complete`.
- */
+/// Runs test methods existing in the given [type].
+///
+/// If there is a "solo" test method in the top-level suite, only "solo" methods
+/// are run.
+///
+/// If there is a "solo" test type, only its test methods are run.
+///
+/// Otherwise all tests methods of all test types are run.
+///
+/// Each method is run with a new instance of [type].
+/// So, [type] should have a default constructor.
+///
+/// If [type] declares method `setUp`, it methods will be invoked before any
+/// test method invocation.
+///
+/// If [type] declares method `tearDown`, it will be invoked after any test
+/// method invocation. If method returns [Future] to test some asynchronous
+/// behavior, then `tearDown` will be invoked in `Future.complete`.
 void defineReflectiveTests(Type type) {
   ClassMirror classMirror = reflectClass(type);
   if (!classMirror.metadata.any((InstanceMirror annotation) =>
       annotation.type.reflectedType == _ReflectiveTest)) {
     String name = MirrorSystem.getName(classMirror.qualifiedName);
-    throw new Exception('Class $name must have annotation "@reflectiveTest" '
+    throw Exception('Class $name must have annotation "@reflectiveTest" '
         'in order to be run by runReflectiveTests.');
   }
 
@@ -104,7 +89,7 @@
   {
     bool isSolo = _hasAnnotationInstance(classMirror, soloTest);
     String className = MirrorSystem.getName(classMirror.simpleName);
-    group = new _Group(isSolo, _combineNames(_currentSuiteName, className));
+    group = _Group(isSolo, _combineNames(_currentSuiteName, className));
     _currentGroups.add(group);
   }
 
@@ -162,9 +147,7 @@
   _addTestsIfTopLevelSuite();
 }
 
-/**
- * If the current suite is the top-level one, add tests to the `test` package.
- */
+/// If the current suite is the top-level one, add tests to the `test` package.
 void _addTestsIfTopLevelSuite() {
   if (_currentSuiteLevel == 0) {
     void runTests({required bool allGroups, required bool allTests}) {
@@ -191,10 +174,8 @@
   }
 }
 
-/**
- * Return the combination of the [base] and [addition] names.
- * If any other two is `null`, then the other one is returned.
- */
+/// Return the combination of the [base] and [addition] names.
+/// If any other two is `null`, then the other one is returned.
 String _combineNames(String base, String addition) {
   if (base.isEmpty) {
     return addition;
@@ -229,33 +210,33 @@
 
 Future<Object?> _invokeSymbolIfExists(
     InstanceMirror instanceMirror, Symbol symbol) {
-  Object? invocationResult = null;
+  Object? invocationResult;
   InstanceMirror? closure;
   try {
     closure = instanceMirror.getField(symbol);
-  } on NoSuchMethodError {}
+  } on NoSuchMethodError {
+    // noop
+  }
 
   if (closure is ClosureMirror) {
     invocationResult = closure.apply([]).reflectee;
   }
-  return new Future.value(invocationResult);
+  return Future.value(invocationResult);
 }
 
-/**
- * Run a test that is expected to fail, and confirm that it fails.
- *
- * This properly handles the following cases:
- * - The test fails by throwing an exception
- * - The test returns a future which completes with an error.
- * - An exception is thrown to the zone handler from a timer task.
- */
+/// Run a test that is expected to fail, and confirm that it fails.
+///
+/// This properly handles the following cases:
+/// - The test fails by throwing an exception
+/// - The test returns a future which completes with an error.
+/// - An exception is thrown to the zone handler from a timer task.
 Future<Object?>? _runFailingTest(ClassMirror classMirror, Symbol symbol) {
   bool passed = false;
   return runZonedGuarded(() {
-    return new Future.sync(() => _runTest(classMirror, symbol)).then<void>((_) {
+    return Future.sync(() => _runTest(classMirror, symbol)).then((_) {
       passed = true;
       test_package.fail('Test passed - expected to fail.');
-    }).catchError((e) {
+    }).catchError((Object e) {
       // if passed, and we call fail(), rethrow this exception
       if (passed) {
         throw e;
@@ -272,64 +253,49 @@
 }
 
 Future<Object?> _runTest(ClassMirror classMirror, Symbol symbol) {
-  InstanceMirror instanceMirror = classMirror.newInstance(new Symbol(''), []);
+  InstanceMirror instanceMirror = classMirror.newInstance(Symbol(''), []);
   return _invokeSymbolIfExists(instanceMirror, #setUp)
       .then((_) => instanceMirror.invoke(symbol, []).reflectee)
       .whenComplete(() => _invokeSymbolIfExists(instanceMirror, #tearDown));
 }
 
-typedef dynamic _TestFunction();
+typedef _TestFunction = dynamic Function();
 
-/**
- * A marker annotation used to annotate test methods which are expected to fail.
- */
+/// A marker annotation used to annotate test methods which are expected to
+/// fail.
 class FailingTest {
-  /**
-   * Initialize this annotation with the given arguments.
-   *
-   * [issue] is a full URI describing the failure and used for tracking.
-   * [reason] is a free form textual description.
-   */
+  /// Initialize this annotation with the given arguments.
+  ///
+  /// [issue] is a full URI describing the failure and used for tracking.
+  /// [reason] is a free form textual description.
   const FailingTest({String? issue, String? reason});
 }
 
-/**
- * A marker annotation used to annotate test methods which are skipped.
- */
+/// A marker annotation used to annotate test methods which are skipped.
 class SkippedTest {
-  /**
-   * Initialize this annotation with the given arguments.
-   *
-   * [issue] is a full URI describing the failure and used for tracking.
-   * [reason] is a free form textual description.
-   */
+  /// Initialize this annotation with the given arguments.
+  ///
+  /// [issue] is a full URI describing the failure and used for tracking.
+  /// [reason] is a free form textual description.
   const SkippedTest({String? issue, String? reason});
 }
 
-/**
- * A marker annotation used to annotate test methods with additional timeout
- * information.
- */
+/// A marker annotation used to annotate test methods with additional timeout
+/// information.
 class TestTimeout {
   final test_package.Timeout _timeout;
 
-  /**
-   * Initialize this annotation with the given timeout.
-   */
+  /// Initialize this annotation with the given timeout.
   const TestTimeout(test_package.Timeout timeout) : _timeout = timeout;
 }
 
-/**
- * A marker annotation used to annotate test methods which are expected to fail
- * when asserts are enabled.
- */
+/// A marker annotation used to annotate test methods which are expected to fail
+/// when asserts are enabled.
 class _AssertFailingTest {
   const _AssertFailingTest();
 }
 
-/**
- * Information about a type based test group.
- */
+/// Information about a type based test group.
 class _Group {
   final bool isSolo;
   final String name;
@@ -341,7 +307,7 @@
 
   void addSkippedTest(String name) {
     var fullName = _combineNames(this.name, name);
-    tests.add(new _Test.skipped(isSolo, fullName));
+    tests.add(_Test.skipped(isSolo, fullName));
   }
 
   void addTest(bool isSolo, String name, MethodMirror memberMirror,
@@ -349,28 +315,22 @@
     var fullName = _combineNames(this.name, name);
     var timeout =
         _getAnnotationInstance(memberMirror, TestTimeout) as TestTimeout?;
-    tests.add(new _Test(isSolo, fullName, function, timeout?._timeout));
+    tests.add(_Test(isSolo, fullName, function, timeout?._timeout));
   }
 }
 
-/**
- * A marker annotation used to instruct dart2js to keep reflection information
- * for the annotated classes.
- */
+/// A marker annotation used to instruct dart2js to keep reflection information
+/// for the annotated classes.
 class _ReflectiveTest {
   const _ReflectiveTest();
 }
 
-/**
- * A marker annotation used to annotate "solo" groups and tests.
- */
+/// A marker annotation used to annotate "solo" groups and tests.
 class _SoloTest {
   const _SoloTest();
 }
 
-/**
- * Information about a test.
- */
+/// Information about a test.
 class _Test {
   final bool isSolo;
   final String name;
diff --git a/pubspec.yaml b/pubspec.yaml
index 1a72733..b374f1d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,11 +1,12 @@
 name: test_reflective_loader
-version: 0.2.0
+version: 0.2.1-dev
 
 description: Support for discovering tests and test suites using reflection.
 homepage: https://github.com/dart-lang/test_reflective_loader
 
 environment:
-  sdk: '>=2.12.0-0 <3.0.0'
+  sdk: '>=2.12.0 <3.0.0'
 
 dependencies:
-  test: '>=1.16.0 <2.0.0'
+  lints: ^1.0.1
+  test: ^1.16.0
diff --git a/test/test_reflective_loader_test.dart b/test/test_reflective_loader_test.dart
index 2c69cce..ea7911f 100644
--- a/test/test_reflective_loader_test.dart
+++ b/test/test_reflective_loader_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// ignore_for_file: non_constant_identifier_names
+
 import 'dart:async';
 
 import 'package:test/test.dart';
@@ -31,7 +33,7 @@
 
   @failingTest
   Future test_fails_throws_async() {
-    return new Future.error('foo');
+    return Future.error('foo');
   }
 
   @skippedTest