@@ -200,6 +200,19 @@ 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) && _dependencies[importedPath] == source) {
208
+ // Throw an error indicating a potential loop.
209
+ var sourceUrl = _absoluteUrlToDependency (source);
210
+ var importedPathUrl = _absoluteUrlToDependency (importedPath);
211
+ throw MigrationException ('Dependency loop detected: ${sourceUrl .item1 } -> ${importedPathUrl .item1 }' );
212
+ }
213
+ _dependencies[source] = importedPath;
214
+ }
215
+
203
216
/// Constructs a new module migration visitor.
204
217
///
205
218
/// [importCache] must be the same one used by [references] .
@@ -1239,6 +1252,13 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
1239
1252
var url = declaration.sourceUrl;
1240
1253
if (url == currentUrl) return null ;
1241
1254
1255
+ // Trace dependencies for loop detection.
1256
+ try {
1257
+ _addDependency (currentUrl, url);
1258
+ } on Exception catch (e) {
1259
+ throw MigrationSourceSpanException (e.toString (), declaration.member.span);
1260
+ }
1261
+
1242
1262
// If we can load [declaration] from a library entrypoint URL, do so. Choose
1243
1263
// the shortest one if there are multiple options.
1244
1264
var libraryUrls = references.libraries[declaration];
0 commit comments