add migration engine sanity check

This adds a sanity check to ensure that DecorateType.forElement
is not called on elements in libraries that are being migrated.

Change-Id: I394004a70e9ca3c9ac22f30e63e8e48a0cd03204
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106922
Reviewed-by: Paul Berry <paulberry@google.com>
diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart
index 5205490..44e3f70 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type.dart
@@ -77,6 +77,13 @@
       }
     }
 
+    // Sanity check:
+    // Ensure the element is not from a library that is being migrated.
+    if (graph.isBeingMigrated(element.source)) {
+      throw 'Internal Error: DecorateType.forElement should not be called'
+          ' for elements being migrated: ${element.runtimeType} :: $element';
+    }
+
     DecoratedType decoratedType;
     if (element is ExecutableElement) {
       decoratedType = decorate(element.type);
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 202fe0a..e472ffd 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -51,6 +51,12 @@
   NodeBuilder(this._variables, this._source, this.listener, this._graph,
       this._typeProvider);
 
+  @override
+  DecoratedType visitCompilationUnit(CompilationUnit node) {
+    _graph.migrating(_source);
+    return super.visitCompilationUnit(node);
+  }
+
   /// Creates and stores a [DecoratedType] object corresponding to the given
   /// [type] AST, and returns it.
   DecoratedType decorateType(TypeAnnotation type, AstNode enclosingNode) {
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index d71920e..6e02eb2 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -97,6 +97,9 @@
   /// node.
   final NullabilityNode never = _NullabilityNodeImmutable('never', false);
 
+  /// Set containing all sources being migrated.
+  final _sourcesBeingMigrated = <Source>{};
+
   /// Records that [sourceNode] is immediately upstream from [destinationNode].
   ///
   /// Returns the edge created by the connection.
@@ -108,6 +111,16 @@
     return _connect(sources, destinationNode, kind, origin);
   }
 
+  /// Determine if [source] is in the code being migrated.
+  bool isBeingMigrated(Source source) {
+    return _sourcesBeingMigrated.contains(source);
+  }
+
+  /// Record source as code that is being migrated.
+  void migrating(Source source) {
+    _sourcesBeingMigrated.add(source);
+  }
+
   /// Determines the nullability of each node in the graph by propagating
   /// nullability information from one node to another.
   ///
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index c378285..92d776d 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -710,6 +710,8 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  @failingTest
+  // DecorateType.forElement is called on element being migrated
   test_instanceCreation_noTypeArguments_noParameters() async {
     var content = '''
 void main() {
@@ -1397,6 +1399,12 @@
     with _ProvisionalApiTestCases {
   @override
   bool get _usePermissiveMode => true;
+
+  // TODO(danrubel): Remove this once the superclass test has been fixed.
+  // This runs in permissive mode but not when permissive mode is disabled.
+  test_instanceCreation_noTypeArguments_noParameters() async {
+    super.test_instanceCreation_noTypeArguments_noParameters();
+  }
 }
 
 /// Tests of the provisional API, where the driver is reset between calls to