@@ -200,6 +200,21 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
200
200
/// The values of the --forward flag.
201
201
final Set <ForwardType > forwards;
202
202
203
+ // Maps direct and indirect dependencies to prevent any potential loops.
204
+ final Map <Uri , Uri > _dependencies = {};
205
+
206
+ void _addDependency (Uri source, Uri importedPath) {
207
+ if (_dependencies.containsKey (importedPath) &&
208
+ _dependencies[importedPath] == source) {
209
+ // Throw an error indicating a potential loop.
210
+ var sourceUrl = _absoluteUrlToDependency (source);
211
+ var importedPathUrl = _absoluteUrlToDependency (importedPath);
212
+ throw MigrationException (
213
+ 'Dependency loop detected: ${sourceUrl .item1 } -> ${importedPathUrl .item1 }' );
214
+ }
215
+ _dependencies[source] = importedPath;
216
+ }
217
+
203
218
/// Constructs a new module migration visitor.
204
219
///
205
220
/// [importCache] must be the same one used by [references] .
@@ -1239,6 +1254,13 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
1239
1254
var url = declaration.sourceUrl;
1240
1255
if (url == currentUrl) return null ;
1241
1256
1257
+ // Trace dependencies for loop detection.
1258
+ try {
1259
+ _addDependency (currentUrl, url);
1260
+ } on Exception catch (e) {
1261
+ throw MigrationSourceSpanException (e.toString (), declaration.member.span);
1262
+ }
1263
+
1242
1264
// If we can load [declaration] from a library entrypoint URL, do so. Choose
1243
1265
// the shortest one if there are multiple options.
1244
1266
var libraryUrls = references.libraries[declaration];
0 commit comments