Add URL to references of a mark target's type arguments.

Fixes https://github.com/dart-lang/mockito/issues/382

All imports in mockito's generated code use import prefixes, and so a prefix always needs to be attached to a reference to a library element (like a class).

Forgetting a URL has been the source of multiple bugs, so this change includes a broader refactor as well to hide code_builder's `refer` function, and instead provide our own.

PiperOrigin-RevId: 368050695
diff --git a/lib/src/builder.dart b/lib/src/builder.dart
index 0f7da31..b145804 100644
--- a/lib/src/builder.dart
+++ b/lib/src/builder.dart
@@ -21,7 +21,13 @@
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/dart/element/visitor.dart';
 import 'package:build/build.dart';
-import 'package:code_builder/code_builder.dart';
+// Do not expose [refer] in the default namespace.
+//
+// [refer] allows a reference to include or not include a URL. Omitting the URL
+// of an element, like a class, has resulted in many bugs. [_MockLibraryInfo]
+// provides a [refer] function and a [referBasic] function. The former requires
+// a URL to be passed.
+import 'package:code_builder/code_builder.dart' hide refer;
 import 'package:dart_style/dart_style.dart';
 import 'package:meta/meta.dart';
 import 'package:mockito/src/version.dart';
@@ -665,7 +671,7 @@
     return Class((cBuilder) {
       cBuilder
         ..name = mockTarget.mockName
-        ..extend = refer('Mock', 'package:mockito/mockito.dart')
+        ..extend = referImported('Mock', 'package:mockito/mockito.dart')
         // TODO(srawlins): Refer to [classToMock] properly, which will yield the
         // appropriate import prefix.
         ..docs.add('/// A class which mocks [$className].')
@@ -685,7 +691,8 @@
         // implements the mock target with said type arguments. For example:
         // `class MockFoo extends Mock implements Foo<int> {}`
         for (var typeArgument in typeToMock.typeArguments) {
-          typeArguments.add(refer(typeArgument.element.name));
+          typeArguments.add(referImported(
+              typeArgument.element.name, _typeImport(typeArgument.element)));
         }
       } else if (classToMock.typeParameters != null) {
         // [typeToMock] is a simple reference to a generic type (for example:
@@ -799,7 +806,7 @@
   /// `throwOnMissingStub`.
   Constructor get _constructorWithThrowOnMissingStub =>
       Constructor((cBuilder) => cBuilder.body =
-          refer('throwOnMissingStub', 'package:mockito/mockito.dart')
+          referImported('throwOnMissingStub', 'package:mockito/mockito.dart')
               .call([refer('this').expression]).statement);
 
   bool _returnTypeIsNonNullable(ExecutableElement method) =>
@@ -1009,7 +1016,7 @@
         fakeClasses.add(Class((cBuilder) {
           cBuilder
             ..name = fakeName
-            ..extend = refer('Fake', 'package:mockito/mockito.dart');
+            ..extend = referImported('Fake', 'package:mockito/mockito.dart');
           if (elementToFake.typeParameters != null) {
             for (var typeParameter in elementToFake.typeParameters) {
               cBuilder.types.add(_typeParameterReference(typeParameter));
@@ -1119,11 +1126,12 @@
         // A top-level function, like `void f() {}` must be referenced by its
         // identifier, rather than a revived value.
         var element = object.toFunctionValue();
-        return refer(revivable.accessor, _typeImport(element));
+        return referImported(revivable.accessor, _typeImport(element));
       } else if (revivable.source.fragment.isEmpty) {
         // We can create this invocation by referring to a const field or
         // top-level variable.
-        return refer(revivable.accessor, _typeImport(object.type.element));
+        return referImported(
+            revivable.accessor, _typeImport(object.type.element));
       }
 
       final name = revivable.source.fragment;
@@ -1135,7 +1143,7 @@
         for (var pair in revivable.namedArguments.entries)
           pair.key: _expressionFromDartObject(pair.value)
       };
-      final type = refer(name, _typeImport(object.type.element));
+      final type = referImported(name, _typeImport(object.type.element));
       if (revivable.accessor.isNotEmpty) {
         return type.constInstanceNamed(
           revivable.accessor,
@@ -1280,7 +1288,7 @@
           ..isNullable = forceNullable || typeSystem.isNullable(type);
       });
     } else {
-      return refer(
+      return referImported(
         type.getDisplayString(withNullability: false),
         _typeImport(type.element),
       );
@@ -1302,6 +1310,16 @@
 
     return assetUris[element];
   }
+
+  /// Returns a [Reference] to [symbol] with [url].
+  ///
+  /// This function overrides [code_builder.refer] so as to ensure that [url] is
+  /// given.
+  static Reference referImported(String symbol, String url) =>
+      Reference(symbol, url);
+
+  /// Returns a [Reference] to [symbol] with no URL.
+  static Reference refer(String symbol) => Reference(symbol);
 }
 
 /// An exception thrown when reviving a potentially deep value in a constant.
diff --git a/test/builder/custom_mocks_test.dart b/test/builder/custom_mocks_test.dart
index fafdcad..059851f 100644
--- a/test/builder/custom_mocks_test.dart
+++ b/test/builder/custom_mocks_test.dart
@@ -124,19 +124,20 @@
       ...annotationsAsset,
       'foo|lib/foo.dart': dedent(r'''
         class Foo<T, U> {}
+        class Bar {}
         '''),
       'foo|test/foo_test.dart': '''
         import 'package:foo/foo.dart';
         import 'package:mockito/annotations.dart';
         @GenerateMocks(
-            [], customMocks: [MockSpec<Foo<int, bool>>(as: #MockFooOfIntBool)])
+            [], customMocks: [MockSpec<Foo<int, Bar>>(as: #MockFooOfIntBar)])
         void main() {}
         '''
     });
     expect(
         mocksContent,
         contains(
-            'class MockFooOfIntBool extends _i1.Mock implements _i2.Foo<int, bool>'));
+            'class MockFooOfIntBar extends _i1.Mock implements _i2.Foo<int, _i2.Bar>'));
   });
 
   test('generates a generic mock class with type arguments but no name',