@@ -108,8 +108,11 @@ class MockBuilder implements Builder {
108
108
b.body.addAll (mockLibraryInfo.mockClasses);
109
109
});
110
110
111
- final emitter = DartEmitter .scoped (
112
- orderDirectives: true , useNullSafetySyntax: sourceLibIsNonNullable);
111
+ final emitter = DartEmitter (
112
+ allocator: _AvoidConflictsAllocator (
113
+ coreConflicts: mockLibraryInfo.coreConflicts),
114
+ orderDirectives: true ,
115
+ useNullSafetySyntax: sourceLibIsNonNullable);
113
116
final rawOutput = mockLibrary.accept (emitter).toString ();
114
117
// The source lib may be pre-null-safety because of an explicit opt-out
115
118
// (`// @dart=2.9`), as opposed to living in a pre-null-safety package. To
@@ -816,13 +819,22 @@ class _MockLibraryInfo {
816
819
/// Asset-resolving while building the mock library.
817
820
final Map <Element , String > assetUris;
818
821
822
+ final LibraryElement ? dartCoreLibrary;
823
+
824
+ /// Names of overridden members which conflict with elements exported from
825
+ /// 'dart:core'.
826
+ ///
827
+ /// Each of these must be imported with a prefix to avoid the conflict.
828
+ final coreConflicts = < String > {};
829
+
819
830
/// Build mock classes for [mockTargets] .
820
831
_MockLibraryInfo (
821
832
Iterable <_MockTarget > mockTargets, {
822
833
required this .assetUris,
823
834
required LibraryElement entryLib,
824
835
required InheritanceManager3 inheritanceManager,
825
- }) {
836
+ }) : dartCoreLibrary = entryLib.importedLibraries
837
+ .firstWhereOrNull ((library) => library.isDartCore) {
826
838
for (final mockTarget in mockTargets) {
827
839
final fallbackGenerators = mockTarget.fallbackGenerators;
828
840
mockClasses.add (_MockClassInfo (
@@ -1013,11 +1025,18 @@ class _MockClassInfo {
1013
1025
if (typeSystem._returnTypeIsNonNullable (method) ||
1014
1026
typeSystem._hasNonNullableParameter (method) ||
1015
1027
_needsOverrideForVoidStub (method)) {
1028
+ _checkForConflictWithCore (method.name);
1016
1029
yield Method ((mBuilder) => _buildOverridingMethod (mBuilder, method));
1017
1030
}
1018
1031
}
1019
1032
}
1020
1033
1034
+ void _checkForConflictWithCore (String name) {
1035
+ if (mockLibraryInfo.dartCoreLibrary? .exportNamespace.get (name) != null ) {
1036
+ mockLibraryInfo.coreConflicts.add (name);
1037
+ }
1038
+ }
1039
+
1021
1040
/// The default behavior of mocks is to return null for unstubbed methods. To
1022
1041
/// use the new behavior of throwing an error, we must explicitly call
1023
1042
/// `throwOnMissingStub` .
@@ -1036,7 +1055,7 @@ class _MockClassInfo {
1036
1055
if (method.isOperator) name = 'operator$name ' ;
1037
1056
builder
1038
1057
..name = name
1039
- ..annotations.addAll ([ refer ('override' )] )
1058
+ ..annotations.add ( referImported ('override' , 'dart:core' ) )
1040
1059
..returns = _typeReference (method.returnType)
1041
1060
..types.addAll (method.typeParameters.map (_typeParameterReference));
1042
1061
@@ -1105,7 +1124,8 @@ class _MockClassInfo {
1105
1124
return ;
1106
1125
}
1107
1126
1108
- final invocation = refer ('Invocation' ).property ('method' ).call ([
1127
+ final invocation =
1128
+ referImported ('Invocation' , 'dart:core' ).property ('method' ).call ([
1109
1129
refer ('#${method .displayName }' ),
1110
1130
literalList (invocationPositionalArgs),
1111
1131
if (invocationNamedArgs.isNotEmpty) literalMap (invocationNamedArgs),
@@ -1202,6 +1222,7 @@ class _MockClassInfo {
1202
1222
return TypeReference ((b) {
1203
1223
b
1204
1224
..symbol = 'Stream'
1225
+ ..url = 'dart:async'
1205
1226
..types.add (elementType);
1206
1227
}).property ('empty' ).call ([]);
1207
1228
} else if (type.isDartCoreString) {
@@ -1224,7 +1245,9 @@ class _MockClassInfo {
1224
1245
/// Returns a reference to [Future] , optionally with a type argument for the
1225
1246
/// value of the Future.
1226
1247
TypeReference _futureReference ([Reference ? valueType]) => TypeReference ((b) {
1227
- b.symbol = 'Future' ;
1248
+ b
1249
+ ..symbol = 'Future'
1250
+ ..url = 'dart:async' ;
1228
1251
if (valueType != null ) {
1229
1252
b.types.add (valueType);
1230
1253
}
@@ -1513,7 +1536,7 @@ class _MockClassInfo {
1513
1536
MethodBuilder builder, PropertyAccessorElement getter) {
1514
1537
builder
1515
1538
..name = getter.displayName
1516
- ..annotations.addAll ([ refer ('override' )] )
1539
+ ..annotations.add ( referImported ('override' , 'dart:core' ) )
1517
1540
..type = MethodType .getter
1518
1541
..returns = _typeReference (getter.returnType);
1519
1542
@@ -1540,7 +1563,8 @@ class _MockClassInfo {
1540
1563
return ;
1541
1564
}
1542
1565
1543
- final invocation = refer ('Invocation' ).property ('getter' ).call ([
1566
+ final invocation =
1567
+ referImported ('Invocation' , 'dart:core' ).property ('getter' ).call ([
1544
1568
refer ('#${getter .displayName }' ),
1545
1569
]);
1546
1570
final namedArgs = {
@@ -1566,7 +1590,7 @@ class _MockClassInfo {
1566
1590
MethodBuilder builder, PropertyAccessorElement setter) {
1567
1591
builder
1568
1592
..name = setter.displayName
1569
- ..annotations.addAll ([ refer ('override' )] )
1593
+ ..annotations.add ( referImported ('override' , 'dart:core' ) )
1570
1594
..type = MethodType .setter;
1571
1595
1572
1596
assert (setter.parameters.length == 1 );
@@ -1576,7 +1600,8 @@ class _MockClassInfo {
1576
1600
..type = _typeReference (parameter.type, forceNullable: true )));
1577
1601
final invocationPositionalArg = refer (parameter.displayName);
1578
1602
1579
- final invocation = refer ('Invocation' ).property ('setter' ).call ([
1603
+ final invocation =
1604
+ referImported ('Invocation' , 'dart:core' ).property ('setter' ).call ([
1580
1605
refer ('#${setter .displayName }' ),
1581
1606
invocationPositionalArg,
1582
1607
]);
@@ -1714,6 +1739,57 @@ class InvalidMockitoAnnotationException implements Exception {
1714
1739
String toString () => 'Invalid @GenerateMocks annotation: $message ' ;
1715
1740
}
1716
1741
1742
+ /// An [Allocator] that avoids conflicts with elements exported from
1743
+ /// 'dart:core'.
1744
+ ///
1745
+ /// This does not prefix _all_ 'dart:core' elements; instead it takes a set of
1746
+ /// names which conflict, and if that is non-empty, generates two import
1747
+ /// directives for 'dart:core':
1748
+ ///
1749
+ /// * an unprefixed import with conflicting names enumerated in the 'hide'
1750
+ /// combinator,
1751
+ /// * a prefixed import which will be the way to reference the conflicting
1752
+ /// names.
1753
+ class _AvoidConflictsAllocator implements Allocator {
1754
+ final _imports = < String , int > {};
1755
+ var _keys = 1 ;
1756
+
1757
+ /// The collection of names of elements which conflict with elements exported
1758
+ /// from 'dart:core'.
1759
+ final Set <String > _coreConflicts;
1760
+
1761
+ _AvoidConflictsAllocator ({required Set <String > coreConflicts})
1762
+ : _coreConflicts = coreConflicts;
1763
+
1764
+ @override
1765
+ String allocate (Reference reference) {
1766
+ final symbol = reference.symbol! ;
1767
+ final url = reference.url;
1768
+ if (url == null ) {
1769
+ return symbol;
1770
+ }
1771
+ if (url == 'dart:core' && ! _coreConflicts.contains (symbol)) {
1772
+ return symbol;
1773
+ }
1774
+ return '_i${_imports .putIfAbsent (url , _nextKey )}.$symbol ' ;
1775
+ }
1776
+
1777
+ int _nextKey () => _keys++ ;
1778
+
1779
+ @override
1780
+ Iterable <Directive > get imports => [
1781
+ if (_imports.containsKey ('dart:core' ))
1782
+ // 'dart:core' is explicitly imported to avoid a conflict between an
1783
+ // overriding member and an element exported by 'dart:core'. We must
1784
+ // add another, unprefixed, import for 'dart:core' which hides the
1785
+ // conflicting names.
1786
+ Directive .import ('dart:core' , hide: _coreConflicts.toList ()),
1787
+ ..._imports.keys.map (
1788
+ (u) => Directive .import (u, as : '_i${_imports [u ]}' ),
1789
+ ),
1790
+ ];
1791
+ }
1792
+
1717
1793
/// A [MockBuilder] instance for use by `build.yaml` .
1718
1794
Builder buildMocks (BuilderOptions options) => MockBuilder ();
1719
1795
0 commit comments