Migration: Created decorated types for synthetic default constructors of non-generic classes.

Partially addresses #37347.

I'll address generic classes in a follow-up CL.

Change-Id: I207465c897f9dfb84848d792cba15ae96c95e394
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107183
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart
index 1fca000..621cea6 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type.dart
@@ -79,6 +79,9 @@
 
     // Sanity check:
     // Ensure the element is not from a library that is being migrated.
+    // If this assertion fires, it probably means that the NodeBuilder failed to
+    // generate the appropriate decorated type for the element when it was
+    // visiting the source file.
     if (graph.isBeingMigrated(element.source)) {
       throw 'Internal Error: DecorateType.forElement should not be called'
           ' for elements being migrated: ${element.runtimeType} :: $element';
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 38d89ef..ec43afa 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -57,12 +57,6 @@
       : _nonNullableObjectType =
             DecoratedType(_typeProvider.objectType, _graph.never);
 
-  @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) {
@@ -84,12 +78,30 @@
     node.typeParameters?.accept(this);
     node.nativeClause?.accept(this);
     node.members.accept(this);
-    _handleSupertypeClauses(
-        node.declaredElement,
-        node.extendsClause?.superclass,
-        node.withClause,
-        node.implementsClause,
-        null);
+    var classElement = node.declaredElement;
+    _handleSupertypeClauses(classElement, node.extendsClause?.superclass,
+        node.withClause, node.implementsClause, null);
+    var constructors = classElement.constructors;
+    if (constructors.length == 1) {
+      var constructorElement = constructors[0];
+      if (constructorElement.isSynthetic) {
+        // Need to create a decorated type for the default constructor.
+        if (classElement.typeParameters.isNotEmpty) {
+          // TODO(paulberry): handle the default constructor for a generic
+          // class.
+        } else {
+          var decoratedReturnType =
+              _createDecoratedTypeForClass(classElement, node);
+          var functionType = DecoratedType(
+              constructorElement.type, _graph.never,
+              returnType: decoratedReturnType,
+              positionalParameters: [],
+              namedParameters: {});
+          _variables.recordDecoratedElementType(
+              constructorElement, functionType);
+        }
+      }
+    }
     return null;
   }
 
@@ -104,6 +116,12 @@
   }
 
   @override
+  DecoratedType visitCompilationUnit(CompilationUnit node) {
+    _graph.migrating(_source);
+    return super.visitCompilationUnit(node);
+  }
+
+  @override
   DecoratedType visitConstructorDeclaration(ConstructorDeclaration node) {
     if (node.factoryKeyword != null) {
       // Factory constructors can return null, but we don't want to propagate a
@@ -335,6 +353,17 @@
     return _NullabilityComment.none;
   }
 
+  DecoratedType _createDecoratedTypeForClass(
+      ClassElement classElement, AstNode node) {
+    if (classElement.typeParameters.isNotEmpty) {
+      // Need to decorate the type parameters appropriately.
+      // TODO(paulberry,brianwilkerson)
+      _unimplemented(node, 'Declaration of a constructor with type parameters');
+    }
+    var decoratedType = new DecoratedType(classElement.type, _graph.never);
+    return decoratedType;
+  }
+
   /// Creates a DecoratedType corresponding to [type], with fresh nullability
   /// nodes everywhere that don't correspond to any source location.  These
   /// nodes can later be unioned with other nodes.
@@ -369,14 +398,8 @@
         _unimplemented(
             parameters.parent, 'Declaration of a factory constructor');
       }
-      if (declaredElement.enclosingElement.typeParameters.isNotEmpty) {
-        // Need to decorate the type parameters appropriately.
-        // TODO(paulberry,brianwilkerson)
-        _unimplemented(parameters.parent,
-            'Declaration of a constructor with type parameters');
-      }
-      decoratedReturnType = new DecoratedType(
-          declaredElement.enclosingElement.type, _graph.never);
+      decoratedReturnType = _createDecoratedTypeForClass(
+          declaredElement.enclosingElement, parameters.parent);
     } else {
       decoratedReturnType = decorateType(returnType, enclosingNode);
     }
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 27d1287..e9aafe1 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -76,6 +76,20 @@
 
 /// Mixin containing test cases for the provisional API.
 mixin _ProvisionalApiTestCases on _ProvisionalApiTestBase {
+  test_class_with_default_constructor() async {
+    var content = '''
+void main() => f(Foo());
+f(Foo f) {}
+class Foo {}
+''';
+    var expected = '''
+void main() => f(Foo());
+f(Foo f) {}
+class Foo {}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_comment_bang_implies_non_null_intent() async {
     var content = '''
 void f(int/*!*/ i) {}
@@ -728,8 +742,6 @@
     await _checkSingleFileChanges(content, expected);
   }
 
-  @failingTest
-  // DecorateType.forElement is called on element being migrated
   test_instanceCreation_noTypeArguments_noParameters() async {
     var content = '''
 void main() {
diff --git a/pkg/nnbd_migration/test/node_builder_test.dart b/pkg/nnbd_migration/test/node_builder_test.dart
index 6ed3113..36b0ce8 100644
--- a/pkg/nnbd_migration/test/node_builder_test.dart
+++ b/pkg/nnbd_migration/test/node_builder_test.dart
@@ -31,6 +31,19 @@
   DecoratedType decoratedTypeParameterBound(String search) => variables
       .decoratedElementType(findNode.typeParameter(search).declaredElement);
 
+  test_class_with_default_constructor() async {
+    await analyze('''
+class C {}
+''');
+    var defaultConstructor = findElement.class_('C').constructors.single;
+    var decoratedConstructorType =
+        variables.decoratedElementType(defaultConstructor);
+    expect(decoratedConstructorType.type.toString(), 'C Function()');
+    expect(decoratedConstructorType.node, same(never));
+    expect(decoratedConstructorType.returnType.type.toString(), 'C');
+    expect(decoratedConstructorType.returnType.node, same(never));
+  }
+
   test_constructor_returnType_implicit_dynamic() async {
     await analyze('''
 class C {