Add scaffolding of code-generation API for Mockito.

PiperOrigin-RevId: 279997785
diff --git a/README.md b/README.md
index 09b6878..5b70df8 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,7 @@
 
 // We can calculate a response at call time.
 var responses = ["Purr", "Meow"];
-when(cat.sound()).thenAnswer((_) => responses.removeAt(0));
+when(cat.sound()).thenAnswer(() => responses.removeAt(0));
 expect(cat.sound(), "Purr");
 expect(cat.sound(), "Meow");
 ```
diff --git a/bin/codegen.dart b/bin/codegen.dart
new file mode 100644
index 0000000..f3ec2b5
--- /dev/null
+++ b/bin/codegen.dart
@@ -0,0 +1,19 @@
+// Copyright 2019 Dart Mockito authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'package:mockito/src/builder.dart';
+
+import 'package:build/build.dart';
+
+Builder buildMocks(BuilderOptions options) => MockBuilder();
diff --git a/build.yaml b/build.yaml
new file mode 100644
index 0000000..755c286
--- /dev/null
+++ b/build.yaml
@@ -0,0 +1,6 @@
+builders:
+  mockBuilder:
+    import: "package:mockito/src/builder.dart"
+    builder_factories: ["buildMocks"]
+    build_extensions: {".dart": [".mocks.dart"]}
+    build_to: source
diff --git a/example/example.dart b/example/example.dart
index 3a708b5..9742c3a 100644
--- a/example/example.dart
+++ b/example/example.dart
@@ -5,9 +5,9 @@
 
 // Real class
 class Cat {
-  String sound() => 'Meow';
+  String sound() => "Meow";
   bool eatFood(String food, {bool hungry}) => true;
-  Future<void> chew() async => print('Chewing...');
+  Future<void> chew() async => print("Chewing...");
   int walk(List<String> places) => 7;
   void sleep() {}
   void hunt(String place, String prey) {}
@@ -42,20 +42,20 @@
     verify(cat.sound());
   });
 
-  test('How about some stubbing?', () {
+  test("How about some stubbing?", () {
     // Unstubbed methods return null.
     expect(cat.sound(), null);
 
     // Stub a method before interacting with it.
-    when(cat.sound()).thenReturn('Purr');
-    expect(cat.sound(), 'Purr');
+    when(cat.sound()).thenReturn("Purr");
+    expect(cat.sound(), "Purr");
 
     // You can call it again.
-    expect(cat.sound(), 'Purr');
+    expect(cat.sound(), "Purr");
 
     // Let's change the stub.
-    when(cat.sound()).thenReturn('Meow');
-    expect(cat.sound(), 'Meow');
+    when(cat.sound()).thenReturn("Meow");
+    expect(cat.sound(), "Meow");
 
     // You can stub getters.
     when(cat.lives).thenReturn(9);
@@ -66,48 +66,48 @@
     expect(() => cat.lives, throwsRangeError);
 
     // We can calculate a response at call time.
-    var responses = ['Purr', 'Meow'];
+    var responses = ["Purr", "Meow"];
     when(cat.sound()).thenAnswer((_) => responses.removeAt(0));
-    expect(cat.sound(), 'Purr');
-    expect(cat.sound(), 'Meow');
+    expect(cat.sound(), "Purr");
+    expect(cat.sound(), "Meow");
   });
 
-  test('Argument matchers', () {
+  test("Argument matchers", () {
     // You can use plain arguments themselves
-    when(cat.eatFood('fish')).thenReturn(true);
+    when(cat.eatFood("fish")).thenReturn(true);
 
     // ... including collections
-    when(cat.walk(['roof', 'tree'])).thenReturn(2);
+    when(cat.walk(["roof", "tree"])).thenReturn(2);
 
     // ... or matchers
-    when(cat.eatFood(argThat(startsWith('dry')))).thenReturn(false);
+    when(cat.eatFood(argThat(startsWith("dry")))).thenReturn(false);
 
     // ... or mix aguments with matchers
-    when(cat.eatFood(argThat(startsWith('dry')), hungry: true))
+    when(cat.eatFood(argThat(startsWith("dry")), hungry: true))
         .thenReturn(true);
-    expect(cat.eatFood('fish'), isTrue);
-    expect(cat.walk(['roof', 'tree']), equals(2));
-    expect(cat.eatFood('dry food'), isFalse);
-    expect(cat.eatFood('dry food', hungry: true), isTrue);
+    expect(cat.eatFood("fish"), isTrue);
+    expect(cat.walk(["roof", "tree"]), equals(2));
+    expect(cat.eatFood("dry food"), isFalse);
+    expect(cat.eatFood("dry food", hungry: true), isTrue);
 
     // You can also verify using an argument matcher.
-    verify(cat.eatFood('fish'));
-    verify(cat.walk(['roof', 'tree']));
-    verify(cat.eatFood(argThat(contains('food'))));
+    verify(cat.eatFood("fish"));
+    verify(cat.walk(["roof", "tree"]));
+    verify(cat.eatFood(argThat(contains("food"))));
 
     // You can verify setters.
     cat.lives = 9;
     verify(cat.lives = 9);
 
-    cat.hunt('backyard', null);
-    verify(cat.hunt('backyard', null)); // OK: no arg matchers.
+    cat.hunt("backyard", null);
+    verify(cat.hunt("backyard", null)); // OK: no arg matchers.
 
-    cat.hunt('backyard', null);
-    verify(cat.hunt(argThat(contains('yard')),
+    cat.hunt("backyard", null);
+    verify(cat.hunt(argThat(contains("yard")),
         argThat(isNull))); // OK: null is wrapped in an arg matcher.
   });
 
-  test('Named arguments', () {
+  test("Named arguments", () {
     // GOOD: argument matchers include their names.
     when(cat.eatFood(any, hungry: anyNamed('hungry'))).thenReturn(true);
     when(cat.eatFood(any, hungry: argThat(isNotNull, named: 'hungry')))
@@ -117,7 +117,7 @@
         .thenReturn(true);
   });
 
-  test('Verifying exact number of invocations / at least x / never', () {
+  test("Verifying exact number of invocations / at least x / never", () {
     cat.sound();
     cat.sound();
     // Exact number of invocations
@@ -133,41 +133,41 @@
     verifyNever(cat.eatFood(any));
   });
 
-  test('Verification in order', () {
-    cat.eatFood('Milk');
+  test("Verification in order", () {
+    cat.eatFood("Milk");
     cat.sound();
-    cat.eatFood('Fish');
-    verifyInOrder([cat.eatFood('Milk'), cat.sound(), cat.eatFood('Fish')]);
+    cat.eatFood("Fish");
+    verifyInOrder([cat.eatFood("Milk"), cat.sound(), cat.eatFood("Fish")]);
   });
 
-  test('Making sure interaction(s) never happened on mock', () {
+  test("Making sure interaction(s) never happened on mock", () {
     verifyZeroInteractions(cat);
   });
 
-  test('Finding redundant invocations', () {
+  test("Finding redundant invocations", () {
     cat.sound();
     verify(cat.sound());
     verifyNoMoreInteractions(cat);
   });
 
-  test('Capturing arguments for further assertions', () {
+  test("Capturing arguments for further assertions", () {
     // Simple capture:
-    cat.eatFood('Fish');
-    expect(verify(cat.eatFood(captureAny)).captured.single, 'Fish');
+    cat.eatFood("Fish");
+    expect(verify(cat.eatFood(captureAny)).captured.single, "Fish");
 
     // Capture multiple calls:
-    cat.eatFood('Milk');
-    cat.eatFood('Fish');
-    expect(verify(cat.eatFood(captureAny)).captured, ['Milk', 'Fish']);
+    cat.eatFood("Milk");
+    cat.eatFood("Fish");
+    expect(verify(cat.eatFood(captureAny)).captured, ["Milk", "Fish"]);
 
     // Conditional capture:
-    cat.eatFood('Milk');
-    cat.eatFood('Fish');
+    cat.eatFood("Milk");
+    cat.eatFood("Fish");
     expect(
-        verify(cat.eatFood(captureThat(startsWith('F')))).captured, ['Fish']);
+        verify(cat.eatFood(captureThat(startsWith("F")))).captured, ["Fish"]);
   });
 
-  test('Waiting for an interaction', () async {
+  test("Waiting for an interaction", () async {
     Future<void> chewHelper(Cat cat) {
       return cat.chew();
     }
@@ -177,15 +177,15 @@
     await untilCalled(cat.chew()); // This completes when cat.chew() is called.
 
     // Waiting for a call that has already happened.
-    cat.eatFood('Fish');
+    cat.eatFood("Fish");
     await untilCalled(cat.eatFood(any)); // This completes immediately.
   });
 
-  test('Fake class', () {
+  test("Fake class", () {
     // Create a new fake Cat at runtime.
     var cat = FakeCat();
 
-    cat.eatFood('Milk'); // Prints 'Fake eat Milk'.
+    cat.eatFood("Milk"); // Prints 'Fake eat Milk'.
     expect(() => cat.sleep(), throwsUnimplementedError);
   });
 }
diff --git a/example/iss/iss.dart b/example/iss/iss.dart
index eef8df4..e932fd9 100644
--- a/example/iss/iss.dart
+++ b/example/iss/iss.dart
@@ -31,7 +31,9 @@
 
   /// Returns the current GPS position in [latitude, longitude] format.
   Future update() async {
-    _ongoingRequest ??= _doUpdate();
+    if (_ongoingRequest == null) {
+      _ongoingRequest = _doUpdate();
+    }
     await _ongoingRequest;
     _ongoingRequest = null;
   }
@@ -39,7 +41,7 @@
   Future _doUpdate() async {
     // Returns the point on the earth directly under the space station
     // at this moment.
-    var rs = await client.get('http://api.open-notify.org/iss-now.json');
+    Response rs = await client.get('http://api.open-notify.org/iss-now.json');
     var data = jsonDecode(rs.body);
     var latitude = double.parse(data['iss_position']['latitude'] as String);
     var longitude = double.parse(data['iss_position']['longitude'] as String);
@@ -58,7 +60,7 @@
   // The ISS is defined to be visible if the distance from the observer to
   // the point on the earth directly under the space station is less than 80km.
   bool get isVisible {
-    var distance = sphericalDistanceKm(locator.currentPosition, observer);
+    double distance = sphericalDistanceKm(locator.currentPosition, observer);
     return distance < 80.0;
   }
 }
diff --git a/example/iss/iss_test.dart b/example/iss/iss_test.dart
index dc4f3cd..3aa2a62 100644
--- a/example/iss/iss_test.dart
+++ b/example/iss/iss_test.dart
@@ -27,18 +27,18 @@
   // verify the calculated distance between them.
   group('Spherical distance', () {
     test('London - Paris', () {
-      var london = Point(51.5073, -0.1277);
-      var paris = Point(48.8566, 2.3522);
-      var d = sphericalDistanceKm(london, paris);
+      Point<double> london = Point(51.5073, -0.1277);
+      Point<double> paris = Point(48.8566, 2.3522);
+      double d = sphericalDistanceKm(london, paris);
       // London should be approximately 343.5km
       // (+/- 0.1km) from Paris.
       expect(d, closeTo(343.5, 0.1));
     });
 
     test('San Francisco - Mountain View', () {
-      var sf = Point(37.783333, -122.416667);
-      var mtv = Point(37.389444, -122.081944);
-      var d = sphericalDistanceKm(sf, mtv);
+      Point<double> sf = Point(37.783333, -122.416667);
+      Point<double> mtv = Point(37.389444, -122.081944);
+      double d = sphericalDistanceKm(sf, mtv);
       // San Francisco should be approximately 52.8km
       // (+/- 0.1km) from Mountain View.
       expect(d, closeTo(52.8, 0.1));
@@ -52,8 +52,8 @@
   // second predefined location. This test runs asynchronously.
   group('ISS spotter', () {
     test('ISS visible', () async {
-      var sf = Point(37.783333, -122.416667);
-      var mtv = Point(37.389444, -122.081944);
+      Point<double> sf = Point(37.783333, -122.416667);
+      Point<double> mtv = Point(37.389444, -122.081944);
       IssLocator locator = MockIssLocator();
       // Mountain View should be visible from San Francisco.
       when(locator.currentPosition).thenReturn(sf);
@@ -63,8 +63,8 @@
     });
 
     test('ISS not visible', () async {
-      var london = Point(51.5073, -0.1277);
-      var mtv = Point(37.389444, -122.081944);
+      Point<double> london = Point(51.5073, -0.1277);
+      Point<double> mtv = Point(37.389444, -122.081944);
       IssLocator locator = MockIssLocator();
       // London should not be visible from Mountain View.
       when(locator.currentPosition).thenReturn(london);
diff --git a/lib/annotations.dart b/lib/annotations.dart
new file mode 100644
index 0000000..bf1f5da
--- /dev/null
+++ b/lib/annotations.dart
@@ -0,0 +1,19 @@
+// Copyright 2019 Dart Mockito authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+class GenerateMocks {
+  final List<Type> classes;
+
+  const GenerateMocks(this.classes);
+}
diff --git a/lib/src/builder.dart b/lib/src/builder.dart
new file mode 100644
index 0000000..16bd59f
--- /dev/null
+++ b/lib/src/builder.dart
@@ -0,0 +1,228 @@
+// Copyright 2019 Dart Mockito authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:build/build.dart';
+import 'package:code_builder/code_builder.dart';
+import 'package:dart_style/dart_style.dart';
+
+/// For a source Dart library, generate the mocks referenced therein.
+///
+/// Given an input library, 'foo.dart', this builder will search the top-level
+/// elements for an annotation, `@GenerateMocks`, from the mockito package. For
+/// example:
+///
+/// ```dart
+/// @GenerateMocks[Foo]
+/// void main() {}
+/// ```
+///
+/// If this builder finds any classes to mock (for example, `Foo`, above), it
+/// will produce a "'.mocks.dart' file with such mocks. In this example,
+/// 'foo.mocks.dart' will be created.
+class MockBuilder implements Builder {
+  @override
+  Future build(BuildStep buildStep) async {
+    final entryLib = await buildStep.inputLibrary;
+    final resolver = buildStep.resolver;
+
+    final mockLibrary = buildStep.inputId.changeExtension('.mocks.dart');
+
+    final mockClasses = <Class>[];
+
+    for (final element in entryLib.topLevelElements) {
+      final annotation = element.metadata.firstWhere(
+          (annotation) =>
+              annotation.element is ConstructorElement &&
+              annotation.element.enclosingElement.name == 'GenerateMocks',
+          orElse: () => null);
+      if (annotation == null) continue;
+      final generateMocksValue = annotation.computeConstantValue();
+      // TODO(srawlins): handle `generateMocksValue == null`?
+      final classesToMock = generateMocksValue.getField('classes');
+      if (classesToMock.isNull)
+        // TODO(srawlins): Log severe instead? How? How to test?
+        throw StateError(
+            'Unresolved "classes" argument for GenerateMocks has errors: '
+            '"${generateMocksValue}');
+      for (final classToMock in classesToMock.toListValue()) {
+        final dartTypeToMock = classToMock.toTypeValue();
+        // TODO(srawlins): Import the library which declares [dartTypeToMock].
+        // TODO(srawlins): Import all supporting libraries, used in type
+        // signatures.
+        _buildCodeForClass(dartTypeToMock, mockClasses);
+      }
+    }
+
+    if (mockClasses.isEmpty) {
+      // Nothing to mock here!
+      return;
+    }
+
+    final emitter = DartEmitter();
+    final mockLibraryContent = DartFormatter()
+        .format(mockClasses.map((c) => c.accept(emitter)).join('\n'));
+
+    await buildStep.writeAsString(mockLibrary, mockLibraryContent);
+  }
+
+  void _buildCodeForClass(final DartType dartType, List<Class> mockClasses) {
+    final elementToMock = dartType.element;
+    // TODO(srawlins): Log/throw here.
+    if (elementToMock is! ClassElement) return;
+    final classToMock = elementToMock as ClassElement;
+    final className = dartType.displayName;
+
+    // TODO(srawlins): Add a dartdoc to the Mock class.
+    final mockClass = Class((cBuilder) {
+      cBuilder
+        ..name = 'Mock$className'
+        ..extend = refer('Mock')
+        ..implements.add(refer(className))
+        ..docs.add('/// A class which mocks [$className].')
+        ..docs.add('///')
+        ..docs.add('/// See the documentation for Mockito\'s code generation '
+            'for more information.');
+      for (final field in classToMock.fields) {
+        if (field.isPrivate || field.isStatic) {
+          continue;
+        }
+        // Handle getters when we handle non-nullable return types.
+        final setter = field.setter;
+        if (setter != null) {
+          cBuilder.methods.add(
+              Method((mBuilder) => _buildOverridingSetter(mBuilder, setter)));
+        }
+      }
+      for (final method in classToMock.methods) {
+        if (method.parameters.isEmpty || method.isPrivate || method.isStatic) {
+          continue;
+        }
+        cBuilder.methods.add(
+            Method((mBuilder) => _buildOverridingMethod(mBuilder, method)));
+      }
+    });
+
+    mockClasses.add(mockClass);
+  }
+
+  /// Build a method which overrides [method], with all non-nullable
+  /// parameter types widened to be nullable.
+  ///
+  /// This new method just calls `super.noSuchMethod`, optionally passing a
+  /// return value for methods with a non-nullable return type.
+  // TODO(srawlins): This method does no widening yet. Widen parameters. Include
+  // tests for typedefs, old-style function parameters, and function types.
+  // TODO(srawlins): This method declares no specific non-null return values
+  // yet.
+  void _buildOverridingMethod(MethodBuilder builder, MethodElement method) {
+    // TODO(srawlins): generator methods like async*, sync*.
+    // TODO(srawlins): abstract methods?
+    builder
+      ..name = method.displayName
+      ..returns = refer(method.returnType.displayName);
+
+    if (method.isAsynchronous) {
+      builder.modifier =
+          method.isGenerator ? MethodModifier.asyncStar : MethodModifier.async;
+    } else if (method.isGenerator) {
+      builder.modifier = MethodModifier.syncStar;
+    }
+
+    // These two variables store the arguments that will be passed to the
+    // [Invocation] built for `noSuchMethod`.
+    final invocationPositionalArgs = <Expression>[];
+    final invocationNamedArgs = <Expression, Expression>{};
+
+    for (final parameter in method.parameters) {
+      if (parameter.isRequiredPositional) {
+        builder.requiredParameters.add(_matchingParameter(parameter));
+        invocationPositionalArgs.add(refer(parameter.displayName));
+      } else if (parameter.isOptionalPositional) {
+        builder.optionalParameters.add(_matchingParameter(parameter));
+        invocationPositionalArgs.add(refer(parameter.displayName));
+      } else if (parameter.isNamed) {
+        builder.optionalParameters.add(_matchingParameter(parameter));
+        invocationNamedArgs[refer('#${parameter.displayName}')] =
+            refer(parameter.displayName);
+      }
+    }
+    // TODO(srawlins): Optionally pass a non-null return value to `noSuchMethod`
+    // which `Mock.noSuchMethod` will simply return, in order to satisfy runtime
+    // type checks.
+    // TODO(srawlins): Handle getter invocations with `Invocation.getter`,
+    // and operators???
+    // TODO(srawlins): Handle generic methods with `Invocation.genericMethod`.
+    final invocation = refer('Invocation').property('method').call([
+      refer('#${method.displayName}'),
+      literalList(invocationPositionalArgs),
+      if (invocationNamedArgs.isNotEmpty) literalMap(invocationNamedArgs),
+    ]);
+    final returnNoSuchMethod =
+        refer('super').property('noSuchMethod').call([invocation]);
+
+    builder.body = returnNoSuchMethod.code;
+  }
+
+  /// Returns a [Parameter] which matches [parameter].
+  Parameter _matchingParameter(ParameterElement parameter) =>
+      Parameter((pBuilder) {
+        pBuilder
+          ..name = parameter.displayName
+          ..type = refer(parameter.type.displayName);
+        if (parameter.isNamed) pBuilder.named = true;
+        if (parameter.defaultValueCode != null) {
+          pBuilder.defaultTo = Code(parameter.defaultValueCode);
+        }
+      });
+
+  /// Build a setter which overrides [setter], widening the single parameter
+  /// type to be nullable if it is non-nullable.
+  ///
+  /// This new setter just calls `super.noSuchMethod`.
+  // TODO(srawlins): This method does no widening yet.
+  void _buildOverridingSetter(
+      MethodBuilder builder, PropertyAccessorElement setter) {
+    builder
+      ..name = setter.displayName
+      ..type = MethodType.setter;
+
+    final invocationPositionalArgs = <Expression>[];
+    // There should only be one required positional parameter. Should we assert
+    // on that? Leave it alone?
+    for (final parameter in setter.parameters) {
+      if (parameter.isRequiredPositional) {
+        builder.requiredParameters.add(Parameter((pBuilder) => pBuilder
+          ..name = parameter.displayName
+          ..type = refer(parameter.type.displayName)));
+        invocationPositionalArgs.add(refer(parameter.displayName));
+      }
+    }
+
+    final invocation = refer('Invocation').property('setter').call([
+      refer('#${setter.displayName}'),
+      literalList(invocationPositionalArgs),
+    ]);
+    final returnNoSuchMethod =
+        refer('super').property('noSuchMethod').call([invocation]);
+
+    builder.body = returnNoSuchMethod.code;
+  }
+
+  @override
+  final buildExtensions = const {
+    '.dart': ['.mocks.dart']
+  };
+}
diff --git a/lib/src/mock.dart b/lib/src/mock.dart
index d83c070..320586e 100644
--- a/lib/src/mock.dart
+++ b/lib/src/mock.dart
@@ -17,7 +17,6 @@
 import 'package:meta/meta.dart';
 import 'package:mockito/src/call_pair.dart';
 import 'package:mockito/src/invocation_matcher.dart';
-// ignore: deprecated_member_use
 import 'package:test_api/test_api.dart';
 // TODO(srawlins): Remove this when we no longer need to check for an
 // incompatiblity between test_api and test.
@@ -38,8 +37,7 @@
 @Deprecated(
     'This function is not a supported function, and may be deleted as early as '
     'Mockito 5.0.0')
-void setDefaultResponse(
-    Mock mock, CallPair<dynamic> Function() defaultResponse) {
+void setDefaultResponse(Mock mock, CallPair<dynamic> defaultResponse()) {
   mock._defaultResponse = defaultResponse;
 }
 
@@ -138,7 +136,7 @@
       const Object().noSuchMethod(invocation);
 
   @override
-  int get hashCode => _givenHashCode ?? 0;
+  int get hashCode => _givenHashCode == null ? 0 : _givenHashCode;
 
   @override
   bool operator ==(other) => (_givenHashCode != null && other is Mock)
@@ -146,7 +144,7 @@
       : identical(this, other);
 
   @override
-  String toString() => _givenName ?? runtimeType.toString();
+  String toString() => _givenName != null ? _givenName : runtimeType.toString();
 
   String _realCallsToString() {
     var stringRepresentations = _realCalls.map((call) => call.toString());
@@ -240,7 +238,7 @@
   factory _InvocationForMatchedArguments(Invocation invocation) {
     if (_storedArgs.isEmpty && _storedNamedArgs.isEmpty) {
       throw StateError(
-          '_InvocationForMatchedArguments called when no ArgMatchers have been saved.');
+          "_InvocationForMatchedArguments called when no ArgMatchers have been saved.");
     }
 
     // Handle named arguments first, so that we can provide useful errors for
@@ -291,7 +289,7 @@
     // Iterate through the stored named args, validate them, and add them to
     // the return map.
     _storedNamedArgs.forEach((name, arg) {
-      var nameSymbol = Symbol(name);
+      Symbol nameSymbol = Symbol(name);
       if (!invocation.namedArguments.containsKey(nameSymbol)) {
         // Clear things out for the next call.
         _storedArgs.clear();
@@ -346,8 +344,8 @@
           'needs to specify the name of the argument it is being used in. For '
           'example: `when(obj.fn(x: anyNamed("x")))`).');
     }
-    var storedIndex = 0;
-    var positionalIndex = 0;
+    int storedIndex = 0;
+    int positionalIndex = 0;
     while (storedIndex < _storedArgs.length &&
         positionalIndex < invocation.positionalArguments.length) {
       var arg = _storedArgs[storedIndex];
@@ -458,7 +456,7 @@
   }
 
   void _captureArguments(Invocation invocation) {
-    var index = 0;
+    int index = 0;
     for (var roleArg in roleInvocation.positionalArguments) {
       var actArg = invocation.positionalArguments[index];
       if (roleArg is ArgMatcher && roleArg._capture) {
@@ -486,7 +484,7 @@
         roleInvocation.namedArguments.length) {
       return false;
     }
-    var index = 0;
+    int index = 0;
     for (var roleArg in roleInvocation.positionalArguments) {
       var actArg = invocation.positionalArguments[index];
       if (!isMatchingArg(roleArg, actArg)) {
@@ -543,7 +541,8 @@
   @override
   String toString() {
     var argString = '';
-    var args = invocation.positionalArguments.map((v) => '$v');
+    var args = invocation.positionalArguments
+        .map((v) => v == null ? "null" : v.toString());
     if (args.any((arg) => arg.contains('\n'))) {
       // As one or more arg contains newlines, put each on its own line, and
       // indent each, for better readability.
@@ -650,18 +649,18 @@
     if (!never && matchingInvocations.isEmpty) {
       var message;
       if (mock._realCalls.isEmpty) {
-        message = 'No matching calls (actually, no calls at all).';
+        message = "No matching calls (actually, no calls at all).";
       } else {
         var otherCalls = mock._realCallsToString();
-        message = 'No matching calls. All calls: $otherCalls';
+        message = "No matching calls. All calls: $otherCalls";
       }
-      fail('$message\n'
-          '(If you called `verify(...).called(0);`, please instead use '
-          '`verifyNever(...);`.)');
+      fail("$message\n"
+          "(If you called `verify(...).called(0);`, please instead use "
+          "`verifyNever(...);`.)");
     }
     if (never && matchingInvocations.isNotEmpty) {
       var calls = mock._realCallsToString();
-      fail('Unexpected calls. All calls: $calls');
+      fail("Unexpected calls. All calls: $calls");
     }
     matchingInvocations.forEach((inv) {
       inv.verified = true;
@@ -874,7 +873,7 @@
       _checkTestApiMismatch();
     }
     expect(callCount, wrapMatcher(matcher),
-        reason: 'Unexpected number of calls');
+        reason: "Unexpected number of calls");
   }
 }
 
@@ -940,12 +939,12 @@
   return <T>(T mock) {
     _verificationInProgress = false;
     if (_verifyCalls.length == 1) {
-      var verifyCall = _verifyCalls.removeLast();
+      _VerifyCall verifyCall = _verifyCalls.removeLast();
       var result = VerificationResult._(verifyCall.matchingInvocations.length);
       verifyCall._checkWith(never);
       return result;
     } else {
-      fail('Used on a non-mockito object');
+      fail("Used on a non-mockito object");
     }
   };
 }
@@ -971,22 +970,23 @@
   _verificationInProgress = true;
   return <T>(List<T> _) {
     _verificationInProgress = false;
-    var dt = DateTime.fromMillisecondsSinceEpoch(0);
+    DateTime dt = DateTime.fromMillisecondsSinceEpoch(0);
     var tmpVerifyCalls = List<_VerifyCall>.from(_verifyCalls);
     _verifyCalls.clear();
-    var matchedCalls = <RealCall>[];
-    for (var verifyCall in tmpVerifyCalls) {
-      var matched = verifyCall._findAfter(dt);
+    List<RealCall> matchedCalls = [];
+    for (_VerifyCall verifyCall in tmpVerifyCalls) {
+      RealCall matched = verifyCall._findAfter(dt);
       if (matched != null) {
         matchedCalls.add(matched);
         dt = matched.timeStamp;
       } else {
-        var mocks = tmpVerifyCalls.map((vc) => vc.mock).toSet();
-        var allInvocations =
+        Set<Mock> mocks =
+            tmpVerifyCalls.map((_VerifyCall vc) => vc.mock).toSet();
+        List<RealCall> allInvocations =
             mocks.expand((m) => m._realCalls).toList(growable: false);
         allInvocations
             .sort((inv1, inv2) => inv1.timeStamp.compareTo(inv2.timeStamp));
-        var otherCalls = '';
+        String otherCalls = "";
         if (allInvocations.isNotEmpty) {
           otherCalls = " All calls: ${allInvocations.join(", ")}";
         }
@@ -1011,7 +1011,7 @@
   if (mock is Mock) {
     var unverified = mock._realCalls.where((inv) => !inv.verified).toList();
     if (unverified.isNotEmpty) {
-      fail('No more calls expected, but following found: ' + unverified.join());
+      fail("No more calls expected, but following found: " + unverified.join());
     }
   } else {
     _throwMockArgumentError('verifyNoMoreInteractions', mock);
@@ -1021,7 +1021,7 @@
 void verifyZeroInteractions(var mock) {
   if (mock is Mock) {
     if (mock._realCalls.isNotEmpty) {
-      fail('No interaction expected, but following found: ' +
+      fail("No interaction expected, but following found: " +
           mock._realCalls.join());
     }
   } else {
@@ -1084,7 +1084,7 @@
 
 /// Print all collected invocations of any mock methods of [mocks].
 void logInvocations(List<Mock> mocks) {
-  var allInvocations =
+  List<RealCall> allInvocations =
       mocks.expand((m) => m._realCalls).toList(growable: false);
   allInvocations.sort((inv1, inv2) => inv1.timeStamp.compareTo(inv2.timeStamp));
   allInvocations.forEach((inv) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 1f438d9..521dd80 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: mockito
-version: 4.1.2-dev
+version: 4.1.1
 
 authors:
   - Dmitriy Fibulwinter <fibulwinter@gmail.com>
@@ -9,10 +9,14 @@
 homepage: https://github.com/dart-lang/mockito
 
 environment:
-  sdk: '>=2.0.0 <3.0.0'
+  sdk: '>=2.3.0 <3.0.0'
 
 dependencies:
+  analyzer: ^0.36.0
+  build: ^1.1.3
+  code_builder: ^3.2.0
   collection: ^1.1.0
+  dart_style: ^1.2.5
   matcher: ^0.12.3
   meta: ^1.0.4
   test_api: ^0.2.1
diff --git a/test/all.dart b/test/all.dart
index ef120e6..0aa5635 100644
--- a/test/all.dart
+++ b/test/all.dart
@@ -15,6 +15,7 @@
 // This file explicitly does _not_ end in `_test.dart`, so that it is not picked
 // up by `pub run test`. It is here for coveralls.
 
+import 'builder_test.dart' as builder_test;
 import 'capture_test.dart' as capture_test;
 import 'invocation_matcher_test.dart' as invocation_matcher_test;
 import 'mockito_test.dart' as mockito_test;
@@ -22,6 +23,7 @@
 import 'verify_test.dart' as verify_test;
 
 void main() {
+  builder_test.main();
   capture_test.main();
   invocation_matcher_test.main();
   mockito_test.main();
diff --git a/test/builder_test.dart b/test/builder_test.dart
new file mode 100644
index 0000000..c2a4224
--- /dev/null
+++ b/test/builder_test.dart
@@ -0,0 +1,266 @@
+// Copyright 2019 Dart Mockito authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'package:build/build.dart';
+import 'package:build_test/build_test.dart';
+import 'package:mockito/src/builder.dart';
+import 'package:test/test.dart';
+
+Builder buildMocks(BuilderOptions options) => MockBuilder();
+
+const annotationsAsset = {
+  'mockito|lib/annotations.dart': '''
+class GenerateMocks {
+  final List<Type> classes;
+
+  const GenerateMocks(this.classes);
+}
+'''
+};
+
+const simpleTestAsset = {
+  'foo|test/foo_test.dart': '''
+import 'package:foo/foo.dart';
+import 'package:mockito/annotations.dart';
+@GenerateMocks([Foo])
+void main() {}
+'''
+};
+
+void main() {
+  test(
+      'generates mock for an imported class but does not override private '
+      'or static methods or methods w/ zero parameters', () async {
+    await testBuilder(
+      buildMocks(BuilderOptions({})),
+      {
+        ...annotationsAsset,
+        ...simpleTestAsset,
+        'foo|lib/foo.dart': dedent(r'''
+        class Foo {
+          int a() => 7;
+          int _b(int x) => 8;
+          static int c(int y) => 9;
+        }
+        '''),
+      },
+      outputs: {
+        'foo|test/foo_test.mocks.dart': dedent(r'''
+        /// A class which mocks [Foo].
+        ///
+        /// See the documentation for Mockito's code generation for more information.
+        class MockFoo extends Mock implements Foo {}
+        '''),
+      },
+    );
+  });
+
+  test(
+      'generates mock for an imported class but does not override private '
+      'or static fields', () async {
+    await testBuilder(
+      buildMocks(BuilderOptions({})),
+      {
+        ...annotationsAsset,
+        ...simpleTestAsset,
+        'foo|lib/foo.dart': dedent(r'''
+        class Foo {
+          int _a;
+          static int b;
+        }
+        '''),
+      },
+      outputs: {
+        'foo|test/foo_test.mocks.dart': dedent(r'''
+        /// A class which mocks [Foo].
+        ///
+        /// See the documentation for Mockito's code generation for more information.
+        class MockFoo extends Mock implements Foo {}
+        '''),
+      },
+    );
+  });
+
+  test(
+      'generates mock for an imported class but does not override any '
+      'extension methods', () async {
+    await testBuilder(
+      buildMocks(BuilderOptions({})),
+      {
+        ...annotationsAsset,
+        ...simpleTestAsset,
+        'foo|lib/foo.dart': dedent(r'''
+        extension X on Foo {
+          dynamic x(int m, String n) => n + 1;
+        }
+        class Foo {
+          dynamic a(int m, String n) => n + 1;
+        }
+        '''),
+      },
+      outputs: {
+        'foo|test/foo_test.mocks.dart': dedent(r'''
+        /// A class which mocks [Foo].
+        ///
+        /// See the documentation for Mockito's code generation for more information.
+        class MockFoo extends Mock implements Foo {
+          dynamic a(int m, String n) =>
+              super.noSuchMethod(Invocation.method(#a, [m, n]));
+        }
+        '''),
+      },
+    );
+  });
+
+  test('generates a mock class and overrides methods parameters', () async {
+    await testBuilder(
+      buildMocks(BuilderOptions({})),
+      {
+        ...annotationsAsset,
+        ...simpleTestAsset,
+        'foo|lib/foo.dart': dedent(r'''
+        class Foo {
+          dynamic a(int m, String n) => n + 1;
+          dynamic b(List<int> list) => list.length;
+          void c(String one, [String two, String three = ""]) => print('$one$two$three');
+          void d(String one, {String two, String three = ""}) => print('$one$two$three');
+          Future<void> e(String s) async => print(s);
+          // TODO(srawlins): Figure out async*; doesn't work yet. `isGenerator`
+          // does not appear to be working.
+          // Stream<void> f(String s) async* => print(s);
+          // Iterable<void> g(String s) sync* => print(s);
+        }
+        '''),
+      },
+      outputs: {
+        'foo|test/foo_test.mocks.dart': dedent(r'''
+        /// A class which mocks [Foo].
+        ///
+        /// See the documentation for Mockito's code generation for more information.
+        class MockFoo extends Mock implements Foo {
+          dynamic a(int m, String n) =>
+              super.noSuchMethod(Invocation.method(#a, [m, n]));
+          dynamic b(List<int> list) =>
+              super.noSuchMethod(Invocation.method(#b, [list]));
+          void c(String one, [String two, String three = ""]) =>
+              super.noSuchMethod(Invocation.method(#c, [one, two, three]));
+          void d(String one, {String two, String three = ""}) => super
+              .noSuchMethod(Invocation.method(#d, [one], {#two: two, #three: three}));
+          Future<void> e(String s) async =>
+              super.noSuchMethod(Invocation.method(#e, [s]));
+        }
+        '''),
+      },
+    );
+  });
+
+  test('generates multiple mock classes', () async {
+    await testBuilder(
+      buildMocks(BuilderOptions({})),
+      {
+        ...annotationsAsset,
+        'foo|lib/foo.dart': dedent(r'''
+        class Foo {
+          dynamic a(int m, String n) => n + 1;
+        }
+        class Bar {
+          dynamic b(List<int> list) => list.length;
+        }
+        '''),
+        'foo|test/foo_test.dart': '''
+        import 'package:foo/foo.dart';
+        import 'package:mockito/annotations.dart';
+        @GenerateMocks([Foo, Bar])
+        void main() {}
+        '''
+      },
+      outputs: {
+        'foo|test/foo_test.mocks.dart': dedent(r'''
+        /// A class which mocks [Foo].
+        ///
+        /// See the documentation for Mockito's code generation for more information.
+        class MockFoo extends Mock implements Foo {
+          dynamic a(int m, String n) =>
+              super.noSuchMethod(Invocation.method(#a, [m, n]));
+        }
+
+        /// A class which mocks [Bar].
+        ///
+        /// See the documentation for Mockito's code generation for more information.
+        class MockBar extends Mock implements Bar {
+          dynamic b(List<int> list) =>
+              super.noSuchMethod(Invocation.method(#b, [list]));
+        }
+        '''),
+      },
+    );
+  });
+
+  test('generates a mock class and overrides getters and setters', () async {
+    await testBuilder(
+      buildMocks(BuilderOptions({})),
+      {
+        ...annotationsAsset,
+        ...simpleTestAsset,
+        'foo|lib/foo.dart': dedent(r'''
+        class Foo {
+          int get a => n + 1;
+          int _b;
+          set b(int value) => _b = value;
+        }
+        '''),
+      },
+      outputs: {
+        // TODO(srawlins): The getter will appear when it has a non-nullable
+        // return type.
+        'foo|test/foo_test.mocks.dart': dedent(r'''
+        /// A class which mocks [Foo].
+        ///
+        /// See the documentation for Mockito's code generation for more information.
+        class MockFoo extends Mock implements Foo {
+          set b(int value) => super.noSuchMethod(Invocation.setter(#b, [value]));
+        }
+        '''),
+      },
+    );
+  });
+  test('throws given bad input', () async {
+    expect(
+        () async => await testBuilder(
+              buildMocks(BuilderOptions({})),
+              {
+                ...annotationsAsset,
+                'foo|lib/foo.dart': dedent(r'''
+                class Foo {}
+                '''),
+                'foo|test/foo_test.dart': dedent('''
+                // missing foo.dart import.
+                import 'package:mockito/annotations.dart';
+                @GenerateMocks([Foo])
+                void main() {}
+                '''),
+              },
+            ),
+        throwsStateError);
+  });
+}
+
+/// Dedent [input], so that each line is shifted to the left, so that the first
+/// line is at the 0 column.
+String dedent(String input) {
+  final indentMatch = RegExp(r'^(\s*)').firstMatch(input);
+  final indent = ''.padRight(indentMatch.group(1).length);
+  return input.splitMapJoin('\n',
+      onNonMatch: (s) => s.replaceFirst(RegExp('^$indent'), ''));
+}
diff --git a/test/capture_test.dart b/test/capture_test.dart
index 7c597ba..09da045 100644
--- a/test/capture_test.dart
+++ b/test/capture_test.dart
@@ -22,7 +22,7 @@
   String methodWithNormalArgs(int x) => 'Real';
   String methodWithListArgs(List<int> x) => 'Real';
   String methodWithPositionalArgs(int x, [int y]) => 'Real';
-  String methodWithTwoNamedArgs(int x, {int y, int z}) => 'Real';
+  String methodWithTwoNamedArgs(int x, {int y, int z}) => "Real";
   set setter(String arg) {
     throw StateError('I must be mocked');
   }
diff --git a/test/deprecated_apis/mockito_test.dart b/test/deprecated_apis/mockito_test.dart
index ab9a4e3..95dbcb4 100644
--- a/test/deprecated_apis/mockito_test.dart
+++ b/test/deprecated_apis/mockito_test.dart
@@ -24,18 +24,18 @@
 
 class _RealClass {
   _RealClass innerObj;
-  String methodWithoutArgs() => 'Real';
-  String methodWithNormalArgs(int x) => 'Real';
-  String methodWithListArgs(List<int> x) => 'Real';
-  String methodWithPositionalArgs(int x, [int y]) => 'Real';
-  String methodWithNamedArgs(int x, {int y}) => 'Real';
-  String methodWithTwoNamedArgs(int x, {int y, int z}) => 'Real';
-  String methodWithObjArgs(_RealClass x) => 'Real';
-  Future<String> methodReturningFuture() => Future.value('Real');
-  Stream<String> methodReturningStream() => Stream.fromIterable(['Real']);
-  String get getter => 'Real';
+  String methodWithoutArgs() => "Real";
+  String methodWithNormalArgs(int x) => "Real";
+  String methodWithListArgs(List<int> x) => "Real";
+  String methodWithPositionalArgs(int x, [int y]) => "Real";
+  String methodWithNamedArgs(int x, {int y}) => "Real";
+  String methodWithTwoNamedArgs(int x, {int y, int z}) => "Real";
+  String methodWithObjArgs(_RealClass x) => "Real";
+  Future<String> methodReturningFuture() => Future.value("Real");
+  Stream<String> methodReturningStream() => Stream.fromIterable(["Real"]);
+  String get getter => "Real";
   set setter(String arg) {
-    throw StateError('I must be mocked');
+    throw StateError("I must be mocked");
   }
 }
 
@@ -54,23 +54,23 @@
 
 class _MockedClass extends Mock implements _RealClass {}
 
-void expectFail(String expectedMessage, void Function() expectedToFail) {
+void expectFail(String expectedMessage, dynamic expectedToFail()) {
   try {
     expectedToFail();
-    fail('It was expected to fail!');
+    fail("It was expected to fail!");
   } catch (e) {
     if (!(e is TestFailure)) {
       rethrow;
     } else {
       if (expectedMessage != e.message) {
-        throw TestFailure('Failed, but with wrong message: ${e.message}');
+        throw TestFailure("Failed, but with wrong message: ${e.message}");
       }
     }
   }
 }
 
-String noMatchingCallsFooter = '(If you called `verify(...).called(0);`, '
-    'please instead use `verifyNever(...);`.)';
+String noMatchingCallsFooter = "(If you called `verify(...).called(0);`, "
+    "please instead use `verifyNever(...);`.)";
 
 void main() {
   _MockedClass mock;
@@ -85,67 +85,67 @@
     resetMockitoState();
   });
 
-  group('when()', () {
-    test('should mock method with argument matcher', () {
+  group("when()", () {
+    test("should mock method with argument matcher", () {
       when(mock.methodWithNormalArgs(typed(argThat(greaterThan(100)))))
-          .thenReturn('A lot!');
+          .thenReturn("A lot!");
       expect(mock.methodWithNormalArgs(100), isNull);
-      expect(mock.methodWithNormalArgs(101), equals('A lot!'));
+      expect(mock.methodWithNormalArgs(101), equals("A lot!"));
     });
 
-    test('should mock method with any argument matcher', () {
-      when(mock.methodWithNormalArgs(typed(any))).thenReturn('A lot!');
-      expect(mock.methodWithNormalArgs(100), equals('A lot!'));
-      expect(mock.methodWithNormalArgs(101), equals('A lot!'));
+    test("should mock method with any argument matcher", () {
+      when(mock.methodWithNormalArgs(typed(any))).thenReturn("A lot!");
+      expect(mock.methodWithNormalArgs(100), equals("A lot!"));
+      expect(mock.methodWithNormalArgs(101), equals("A lot!"));
     });
 
-    test('should mock method with any list argument matcher', () {
-      when(mock.methodWithListArgs(typed(any))).thenReturn('A lot!');
-      expect(mock.methodWithListArgs([42]), equals('A lot!'));
-      expect(mock.methodWithListArgs([43]), equals('A lot!'));
+    test("should mock method with any list argument matcher", () {
+      when(mock.methodWithListArgs(typed(any))).thenReturn("A lot!");
+      expect(mock.methodWithListArgs([42]), equals("A lot!"));
+      expect(mock.methodWithListArgs([43]), equals("A lot!"));
     });
 
-    test('should mock method with mix of argument matchers and real things',
+    test("should mock method with mix of argument matchers and real things",
         () {
       when(mock.methodWithPositionalArgs(typed(argThat(greaterThan(100))), 17))
-          .thenReturn('A lot with 17');
+          .thenReturn("A lot with 17");
       expect(mock.methodWithPositionalArgs(100, 17), isNull);
       expect(mock.methodWithPositionalArgs(101, 18), isNull);
-      expect(mock.methodWithPositionalArgs(101, 17), equals('A lot with 17'));
+      expect(mock.methodWithPositionalArgs(101, 17), equals("A lot with 17"));
     });
 
     //no need to mock setter, except if we will have spies later...
-    test('should mock method with thrown result', () {
+    test("should mock method with thrown result", () {
       when(mock.methodWithNormalArgs(typed(any))).thenThrow(StateError('Boo'));
       expect(() => mock.methodWithNormalArgs(42), throwsStateError);
     });
 
-    test('should mock method with calculated result', () {
+    test("should mock method with calculated result", () {
       when(mock.methodWithNormalArgs(typed(any))).thenAnswer(
           (Invocation inv) => inv.positionalArguments[0].toString());
-      expect(mock.methodWithNormalArgs(43), equals('43'));
-      expect(mock.methodWithNormalArgs(42), equals('42'));
+      expect(mock.methodWithNormalArgs(43), equals("43"));
+      expect(mock.methodWithNormalArgs(42), equals("42"));
     });
 
-    test('should mock method with calculated result', () {
+    test("should mock method with calculated result", () {
       when(mock.methodWithNormalArgs(typed(argThat(equals(43)))))
-          .thenReturn('43');
+          .thenReturn("43");
       when(mock.methodWithNormalArgs(typed(argThat(equals(42)))))
-          .thenReturn('42');
-      expect(mock.methodWithNormalArgs(43), equals('43'));
+          .thenReturn("42");
+      expect(mock.methodWithNormalArgs(43), equals("43"));
     });
 
-    test('should mock hashCode', () {
+    test("should mock hashCode", () {
       named(mock, hashCode: 42);
       expect(mock.hashCode, equals(42));
     });
 
-    test('should have toString as name when it is not mocked', () {
-      named(mock, name: 'Cat');
-      expect(mock.toString(), equals('Cat'));
+    test("should have toString as name when it is not mocked", () {
+      named(mock, name: "Cat");
+      expect(mock.toString(), equals("Cat"));
     });
 
-    test('should mock equals between mocks when givenHashCode is equals', () {
+    test("should mock equals between mocks when givenHashCode is equals", () {
       var anotherMock = named(_MockedClass(), hashCode: 42);
       named(mock, hashCode: 42);
       expect(mock == anotherMock, isTrue);
diff --git a/test/deprecated_apis/until_called_test.dart b/test/deprecated_apis/until_called_test.dart
index f4e6801..92ed487 100644
--- a/test/deprecated_apis/until_called_test.dart
+++ b/test/deprecated_apis/until_called_test.dart
@@ -86,7 +86,8 @@
   });
 
   group('untilCalled', () {
-    var streamController = StreamController<CallMethodsEvent>.broadcast();
+    StreamController<CallMethodsEvent> streamController =
+        StreamController.broadcast();
 
     group('on methods already called', () {
       test('waits for method with normal args', () async {
diff --git a/test/deprecated_apis/verify_test.dart b/test/deprecated_apis/verify_test.dart
index 74cfdcb..a8c870c 100644
--- a/test/deprecated_apis/verify_test.dart
+++ b/test/deprecated_apis/verify_test.dart
@@ -57,7 +57,7 @@
 
 class _MockedClass extends Mock implements _RealClass {}
 
-void expectFail(String expectedMessage, void Function() expectedToFail) {
+void expectFail(String expectedMessage, dynamic expectedToFail()) {
   try {
     expectedToFail();
     fail('It was expected to fail!');
diff --git a/test/invocation_matcher_test.dart b/test/invocation_matcher_test.dart
index dc5bb52..12eae07 100644
--- a/test/invocation_matcher_test.dart
+++ b/test/invocation_matcher_test.dart
@@ -66,9 +66,9 @@
       shouldFail(
         call1,
         isInvocation(call3),
-        'Expected: lie(<false>) '
+        "Expected: lie(<false>) "
         "Actual: <Instance of '${call3.runtimeType}'> "
-        'Which: Does not match lie(<true>)',
+        "Which: Does not match lie(<true>)",
       );
     });
 
@@ -102,9 +102,9 @@
         call1,
         isInvocation(call3),
         // RegExp needed because of https://github.com/dart-lang/sdk/issues/33565
-        RegExp('Expected: set value=? <false> '
+        RegExp("Expected: set value=? <false> "
             "Actual: <Instance of '${call3.runtimeType}'> "
-            'Which: Does not match set value=? <true>'),
+            "Which: Does not match set value=? <true>"),
       );
     });
   });
@@ -118,7 +118,7 @@
       shouldFail(
         call,
         invokes(#say, positionalArguments: [isNull]),
-        'Expected: say(null) '
+        "Expected: say(null) "
         "Actual: <Instance of '${call.runtimeType}'> "
         "Which: Does not match say('Hello')",
       );
diff --git a/test/mockito_test.dart b/test/mockito_test.dart
index e31cde2..1b80150 100644
--- a/test/mockito_test.dart
+++ b/test/mockito_test.dart
@@ -21,16 +21,16 @@
 
 class _RealClass {
   _RealClass innerObj;
-  String methodWithoutArgs() => 'Real';
-  String methodWithNormalArgs(int x) => 'Real';
-  String methodWithListArgs(List<int> x) => 'Real';
-  String methodWithPositionalArgs(int x, [int y]) => 'Real';
-  String methodWithNamedArgs(int x, {int y}) => 'Real';
-  String methodWithTwoNamedArgs(int x, {int y, int z}) => 'Real';
-  String methodWithObjArgs(_RealClass x) => 'Real';
-  Future<String> methodReturningFuture() => Future.value('Real');
-  Stream<String> methodReturningStream() => Stream.fromIterable(['Real']);
-  String get getter => 'Real';
+  String methodWithoutArgs() => "Real";
+  String methodWithNormalArgs(int x) => "Real";
+  String methodWithListArgs(List<int> x) => "Real";
+  String methodWithPositionalArgs(int x, [int y]) => "Real";
+  String methodWithNamedArgs(int x, {int y}) => "Real";
+  String methodWithTwoNamedArgs(int x, {int y, int z}) => "Real";
+  String methodWithObjArgs(_RealClass x) => "Real";
+  Future<String> methodReturningFuture() => Future.value("Real");
+  Stream<String> methodReturningStream() => Stream.fromIterable(["Real"]);
+  String get getter => "Real";
 }
 
 abstract class _Foo {
@@ -43,30 +43,30 @@
 
   String baz();
 
-  String quux() => 'Real';
+  String quux() => "Real";
 }
 
 class _MockFoo extends _AbstractFoo with Mock {}
 
 class _MockedClass extends Mock implements _RealClass {}
 
-void expectFail(String expectedMessage, void Function() expectedToFail) {
+void expectFail(String expectedMessage, dynamic expectedToFail()) {
   try {
     expectedToFail();
-    fail('It was expected to fail!');
+    fail("It was expected to fail!");
   } catch (e) {
     if (!(e is TestFailure)) {
       rethrow;
     } else {
       if (expectedMessage != e.message) {
-        throw TestFailure('Failed, but with wrong message: ${e.message}');
+        throw TestFailure("Failed, but with wrong message: ${e.message}");
       }
     }
   }
 }
 
-String noMatchingCallsFooter = '(If you called `verify(...).called(0);`, '
-    'please instead use `verifyNever(...);`.)';
+String noMatchingCallsFooter = "(If you called `verify(...).called(0);`, "
+    "please instead use `verifyNever(...);`.)";
 
 void main() {
   _MockedClass mock;
@@ -83,229 +83,229 @@
     resetMockitoState();
   });
 
-  group('mixin support', () {
-    test('should work', () {
+  group("mixin support", () {
+    test("should work", () {
       var foo = _MockFoo();
       when(foo.baz()).thenReturn('baz');
       expect(foo.bar(), 'baz');
     });
   });
 
-  group('when()', () {
-    test('should mock method without args', () {
-      when(mock.methodWithoutArgs()).thenReturn('A');
-      expect(mock.methodWithoutArgs(), equals('A'));
+  group("when()", () {
+    test("should mock method without args", () {
+      when(mock.methodWithoutArgs()).thenReturn("A");
+      expect(mock.methodWithoutArgs(), equals("A"));
     });
 
-    test('should mock method with normal args', () {
-      when(mock.methodWithNormalArgs(42)).thenReturn('Ultimate Answer');
+    test("should mock method with normal args", () {
+      when(mock.methodWithNormalArgs(42)).thenReturn("Ultimate Answer");
       expect(mock.methodWithNormalArgs(43), isNull);
-      expect(mock.methodWithNormalArgs(42), equals('Ultimate Answer'));
+      expect(mock.methodWithNormalArgs(42), equals("Ultimate Answer"));
     });
 
-    test('should mock method with mock args', () {
+    test("should mock method with mock args", () {
       var m1 = _MockedClass();
-      when(mock.methodWithObjArgs(m1)).thenReturn('Ultimate Answer');
+      when(mock.methodWithObjArgs(m1)).thenReturn("Ultimate Answer");
       expect(mock.methodWithObjArgs(_MockedClass()), isNull);
-      expect(mock.methodWithObjArgs(m1), equals('Ultimate Answer'));
+      expect(mock.methodWithObjArgs(m1), equals("Ultimate Answer"));
     });
 
-    test('should mock method with positional args', () {
-      when(mock.methodWithPositionalArgs(42, 17)).thenReturn('Answer and...');
+    test("should mock method with positional args", () {
+      when(mock.methodWithPositionalArgs(42, 17)).thenReturn("Answer and...");
       expect(mock.methodWithPositionalArgs(42), isNull);
       expect(mock.methodWithPositionalArgs(42, 18), isNull);
-      expect(mock.methodWithPositionalArgs(42, 17), equals('Answer and...'));
+      expect(mock.methodWithPositionalArgs(42, 17), equals("Answer and..."));
     });
 
-    test('should mock method with named args', () {
-      when(mock.methodWithNamedArgs(42, y: 17)).thenReturn('Why answer?');
+    test("should mock method with named args", () {
+      when(mock.methodWithNamedArgs(42, y: 17)).thenReturn("Why answer?");
       expect(mock.methodWithNamedArgs(42), isNull);
       expect(mock.methodWithNamedArgs(42, y: 18), isNull);
-      expect(mock.methodWithNamedArgs(42, y: 17), equals('Why answer?'));
+      expect(mock.methodWithNamedArgs(42, y: 17), equals("Why answer?"));
     });
 
-    test('should mock method with List args', () {
-      when(mock.methodWithListArgs([42])).thenReturn('Ultimate answer');
+    test("should mock method with List args", () {
+      when(mock.methodWithListArgs([42])).thenReturn("Ultimate answer");
       expect(mock.methodWithListArgs([43]), isNull);
-      expect(mock.methodWithListArgs([42]), equals('Ultimate answer'));
+      expect(mock.methodWithListArgs([42]), equals("Ultimate answer"));
     });
 
-    test('should mock method with argument matcher', () {
+    test("should mock method with argument matcher", () {
       when(mock.methodWithNormalArgs(argThat(greaterThan(100))))
-          .thenReturn('A lot!');
+          .thenReturn("A lot!");
       expect(mock.methodWithNormalArgs(100), isNull);
-      expect(mock.methodWithNormalArgs(101), equals('A lot!'));
+      expect(mock.methodWithNormalArgs(101), equals("A lot!"));
     });
 
-    test('should mock method with any argument matcher', () {
-      when(mock.methodWithNormalArgs(any)).thenReturn('A lot!');
-      expect(mock.methodWithNormalArgs(100), equals('A lot!'));
-      expect(mock.methodWithNormalArgs(101), equals('A lot!'));
+    test("should mock method with any argument matcher", () {
+      when(mock.methodWithNormalArgs(any)).thenReturn("A lot!");
+      expect(mock.methodWithNormalArgs(100), equals("A lot!"));
+      expect(mock.methodWithNormalArgs(101), equals("A lot!"));
     });
 
-    test('should mock method with any list argument matcher', () {
-      when(mock.methodWithListArgs(any)).thenReturn('A lot!');
-      expect(mock.methodWithListArgs([42]), equals('A lot!'));
-      expect(mock.methodWithListArgs([43]), equals('A lot!'));
+    test("should mock method with any list argument matcher", () {
+      when(mock.methodWithListArgs(any)).thenReturn("A lot!");
+      expect(mock.methodWithListArgs([42]), equals("A lot!"));
+      expect(mock.methodWithListArgs([43]), equals("A lot!"));
     });
 
-    test('should mock method with multiple named args and matchers', () {
+    test("should mock method with multiple named args and matchers", () {
       when(mock.methodWithTwoNamedArgs(any, y: anyNamed('y')))
-          .thenReturn('x y');
+          .thenReturn("x y");
       when(mock.methodWithTwoNamedArgs(any, z: anyNamed('z')))
-          .thenReturn('x z');
+          .thenReturn("x z");
       if (isNsmForwarding) {
-        expect(mock.methodWithTwoNamedArgs(42), 'x z');
+        expect(mock.methodWithTwoNamedArgs(42), "x z");
       } else {
         expect(mock.methodWithTwoNamedArgs(42), isNull);
       }
-      expect(mock.methodWithTwoNamedArgs(42, y: 18), equals('x y'));
-      expect(mock.methodWithTwoNamedArgs(42, z: 17), equals('x z'));
+      expect(mock.methodWithTwoNamedArgs(42, y: 18), equals("x y"));
+      expect(mock.methodWithTwoNamedArgs(42, z: 17), equals("x z"));
       expect(mock.methodWithTwoNamedArgs(42, y: 18, z: 17), isNull);
       when(mock.methodWithTwoNamedArgs(any, y: anyNamed('y'), z: anyNamed('z')))
-          .thenReturn('x y z');
-      expect(mock.methodWithTwoNamedArgs(42, y: 18, z: 17), equals('x y z'));
+          .thenReturn("x y z");
+      expect(mock.methodWithTwoNamedArgs(42, y: 18, z: 17), equals("x y z"));
     });
 
-    test('should mock method with mix of argument matchers and real things',
+    test("should mock method with mix of argument matchers and real things",
         () {
       when(mock.methodWithPositionalArgs(argThat(greaterThan(100)), 17))
-          .thenReturn('A lot with 17');
+          .thenReturn("A lot with 17");
       expect(mock.methodWithPositionalArgs(100, 17), isNull);
       expect(mock.methodWithPositionalArgs(101, 18), isNull);
-      expect(mock.methodWithPositionalArgs(101, 17), equals('A lot with 17'));
+      expect(mock.methodWithPositionalArgs(101, 17), equals("A lot with 17"));
     });
 
-    test('should mock getter', () {
-      when(mock.getter).thenReturn('A');
-      expect(mock.getter, equals('A'));
+    test("should mock getter", () {
+      when(mock.getter).thenReturn("A");
+      expect(mock.getter, equals("A"));
     });
 
-    test('should have hashCode when it is not mocked', () {
+    test("should have hashCode when it is not mocked", () {
       expect(mock.hashCode, isNotNull);
     });
 
-    test('should have default toString when it is not mocked', () {
+    test("should have default toString when it is not mocked", () {
       expect(mock.toString(), equals('_MockedClass'));
     });
 
-    test('should use identical equality between it is not mocked', () {
+    test("should use identical equality between it is not mocked", () {
       var anotherMock = _MockedClass();
       expect(mock == anotherMock, isFalse);
       expect(mock == mock, isTrue);
     });
 
-    test('should mock method with thrown result', () {
+    test("should mock method with thrown result", () {
       when(mock.methodWithNormalArgs(any)).thenThrow(StateError('Boo'));
       expect(() => mock.methodWithNormalArgs(42), throwsStateError);
     });
 
-    test('should mock method with calculated result', () {
+    test("should mock method with calculated result", () {
       when(mock.methodWithNormalArgs(any)).thenAnswer(
           (Invocation inv) => inv.positionalArguments[0].toString());
-      expect(mock.methodWithNormalArgs(43), equals('43'));
-      expect(mock.methodWithNormalArgs(42), equals('42'));
+      expect(mock.methodWithNormalArgs(43), equals("43"));
+      expect(mock.methodWithNormalArgs(42), equals("42"));
     });
 
-    test('should return mock to make simple oneline mocks', () {
+    test("should return mock to make simple oneline mocks", () {
       _RealClass mockWithSetup = _MockedClass();
-      when(mockWithSetup.methodWithoutArgs()).thenReturn('oneline');
-      expect(mockWithSetup.methodWithoutArgs(), equals('oneline'));
+      when(mockWithSetup.methodWithoutArgs()).thenReturn("oneline");
+      expect(mockWithSetup.methodWithoutArgs(), equals("oneline"));
     });
 
-    test('should use latest matching when definition', () {
-      when(mock.methodWithoutArgs()).thenReturn('A');
-      when(mock.methodWithoutArgs()).thenReturn('B');
-      expect(mock.methodWithoutArgs(), equals('B'));
+    test("should use latest matching when definition", () {
+      when(mock.methodWithoutArgs()).thenReturn("A");
+      when(mock.methodWithoutArgs()).thenReturn("B");
+      expect(mock.methodWithoutArgs(), equals("B"));
     });
 
-    test('should mock method with calculated result', () {
-      when(mock.methodWithNormalArgs(argThat(equals(43)))).thenReturn('43');
-      when(mock.methodWithNormalArgs(argThat(equals(42)))).thenReturn('42');
-      expect(mock.methodWithNormalArgs(43), equals('43'));
+    test("should mock method with calculated result", () {
+      when(mock.methodWithNormalArgs(argThat(equals(43)))).thenReturn("43");
+      when(mock.methodWithNormalArgs(argThat(equals(42)))).thenReturn("42");
+      expect(mock.methodWithNormalArgs(43), equals("43"));
     });
 
     // Error path tests.
-    test('should throw if `when` is called while stubbing', () {
+    test("should throw if `when` is called while stubbing", () {
       expect(() {
         var responseHelper = () {
           var mock2 = _MockedClass();
-          when(mock2.getter).thenReturn('A');
+          when(mock2.getter).thenReturn("A");
           return mock2;
         };
         when(mock.innerObj).thenReturn(responseHelper());
       }, throwsStateError);
     });
 
-    test('thenReturn throws if provided Future', () {
+    test("thenReturn throws if provided Future", () {
       expect(
           () => when(mock.methodReturningFuture())
-              .thenReturn(Future.value('stub')),
+              .thenReturn(Future.value("stub")),
           throwsArgumentError);
     });
 
-    test('thenReturn throws if provided Stream', () {
+    test("thenReturn throws if provided Stream", () {
       expect(
           () => when(mock.methodReturningStream())
-              .thenReturn(Stream.fromIterable(['stub'])),
+              .thenReturn(Stream.fromIterable(["stub"])),
           throwsArgumentError);
     });
 
-    test('thenAnswer supports stubbing method returning a Future', () async {
+    test("thenAnswer supports stubbing method returning a Future", () async {
       when(mock.methodReturningFuture())
-          .thenAnswer((_) => Future.value('stub'));
+          .thenAnswer((_) => Future.value("stub"));
 
-      expect(await mock.methodReturningFuture(), 'stub');
+      expect(await mock.methodReturningFuture(), "stub");
     });
 
-    test('thenAnswer supports stubbing method returning a Stream', () async {
+    test("thenAnswer supports stubbing method returning a Stream", () async {
       when(mock.methodReturningStream())
-          .thenAnswer((_) => Stream.fromIterable(['stub']));
+          .thenAnswer((_) => Stream.fromIterable(["stub"]));
 
-      expect(await mock.methodReturningStream().toList(), ['stub']);
+      expect(await mock.methodReturningStream().toList(), ["stub"]);
     });
 
-    test('should throw if named matcher is passed as the wrong name', () {
+    test("should throw if named matcher is passed as the wrong name", () {
       expect(() {
-        when(mock.methodWithNamedArgs(argThat(equals(42)), y: anyNamed('z')))
-            .thenReturn('99');
+        when(mock.methodWithNamedArgs(argThat(equals(42)), y: anyNamed("z")))
+            .thenReturn("99");
       }, throwsArgumentError);
     });
 
-    test('should throw if attempting to stub a real method', () {
+    test("should throw if attempting to stub a real method", () {
       var foo = _MockFoo();
       expect(() {
-        when(foo.quux()).thenReturn('Stub');
+        when(foo.quux()).thenReturn("Stub");
       }, throwsStateError);
     });
   });
 
-  group('throwOnMissingStub', () {
-    test('should throw when a mock was called without a matching stub', () {
+  group("throwOnMissingStub", () {
+    test("should throw when a mock was called without a matching stub", () {
       throwOnMissingStub(mock);
-      when(mock.methodWithNormalArgs(42)).thenReturn('Ultimate Answer');
+      when(mock.methodWithNormalArgs(42)).thenReturn("Ultimate Answer");
       expect(
         () => (mock).methodWithoutArgs(),
         throwsNoSuchMethodError,
       );
     });
 
-    test('should not throw when a mock was called with a matching stub', () {
+    test("should not throw when a mock was called with a matching stub", () {
       throwOnMissingStub(mock);
-      when(mock.methodWithoutArgs()).thenReturn('A');
+      when(mock.methodWithoutArgs()).thenReturn("A");
       expect(() => mock.methodWithoutArgs(), returnsNormally);
     });
   });
 
   test(
-      'reports an error when using an argument matcher outside of stubbing or '
-      'verification', () {
+      "reports an error when using an argument matcher outside of stubbing or "
+      "verification", () {
     expect(() => mock.methodWithNormalArgs(any), throwsArgumentError);
   });
 
   test(
-      'reports an error when using an argument matcher in a position other '
-      'than an argument for the stubbed method', () {
+      "reports an error when using an argument matcher in a position other "
+      "than an argument for the stubbed method", () {
     expect(() => when(mock.methodWithListArgs(List.filled(7, any))),
         throwsArgumentError);
   });
diff --git a/test/until_called_test.dart b/test/until_called_test.dart
index 4a0b03f..634c59c 100644
--- a/test/until_called_test.dart
+++ b/test/until_called_test.dart
@@ -81,7 +81,8 @@
   });
 
   group('untilCalled', () {
-    var streamController = StreamController<CallMethodsEvent>.broadcast();
+    StreamController<CallMethodsEvent> streamController =
+        StreamController.broadcast();
 
     group('on methods already called', () {
       test('waits for method without args', () async {
diff --git a/test/verify_test.dart b/test/verify_test.dart
index 7622a2b..0c41c29 100644
--- a/test/verify_test.dart
+++ b/test/verify_test.dart
@@ -54,7 +54,7 @@
 
 class _MockedClass extends Mock implements _RealClass {}
 
-void expectFail(Pattern expectedMessage, void Function() expectedToFail) {
+void expectFail(Pattern expectedMessage, dynamic expectedToFail()) {
   try {
     expectedToFail();
     fail('It was expected to fail!');