[kernel] Add ability to (de)serialize ConstructorInvocation

Change-Id: Ia25e1800c820c63a7e48818860ed3110de5473ea
Reviewed-on: https://dart-review.googlesource.com/c/90384
Reviewed-by: Daniel Hillerström <hillerstrom@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index e6f6503..226f774 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -109,6 +109,12 @@
   String visitDirectMethodInvocation(DirectMethodInvocation _) {
     return "invoke-direct-method";
   }
+
+  String visitConstructorInvocation(ConstructorInvocation expression) {
+    return expression.isConst
+        ? "invoke-const-constructor"
+        : "invoke-constructor";
+  }
 }
 
 TextSerializer<InvalidExpression> invalidExpressionSerializer = new Wrapped(
@@ -664,6 +670,37 @@
       tuple.first, tuple.second.getReference(), tuple.third);
 }
 
+TextSerializer<ConstructorInvocation> constructorInvocationSerializer =
+    new Wrapped(
+        unwrapConstructorInvocation,
+        wrapConstructorInvocation,
+        new Tuple2Serializer(
+            const CanonicalNameSerializer(), argumentsSerializer));
+
+Tuple2<CanonicalName, Arguments> unwrapConstructorInvocation(
+    ConstructorInvocation expression) {
+  return new Tuple2(
+      expression.targetReference.canonicalName, expression.arguments);
+}
+
+ConstructorInvocation wrapConstructorInvocation(
+    Tuple2<CanonicalName, Arguments> tuple) {
+  return new ConstructorInvocation.byReference(
+      tuple.first.getReference(), tuple.second,
+      isConst: false);
+}
+
+TextSerializer<ConstructorInvocation> constConstructorInvocationSerializer =
+    new Wrapped(unwrapConstructorInvocation, wrapConstConstructorInvocation,
+        Tuple2Serializer(const CanonicalNameSerializer(), argumentsSerializer));
+
+ConstructorInvocation wrapConstConstructorInvocation(
+    Tuple2<CanonicalName, Arguments> tuple) {
+  return new ConstructorInvocation.byReference(
+      tuple.first.getReference(), tuple.second,
+      isConst: true);
+}
+
 Case<Expression> expressionSerializer =
     new Case.uninitialized(const ExpressionTagger());
 
@@ -877,6 +914,8 @@
     "invoke-static",
     "invoke-const-static",
     "invoke-direct-method",
+    "invoke-constructor",
+    "invoke-const-constructor",
   ]);
   expressionSerializer.serializers.addAll([
     stringLiteralSerializer,
@@ -920,6 +959,8 @@
     staticInvocationSerializer,
     constStaticInvocationSerializer,
     directMethodInvocationSerializer,
+    constructorInvocationSerializer,
+    constConstructorInvocationSerializer,
   ]);
   dartTypeSerializer.tags.addAll([
     "invalid",
diff --git a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
index 0976525..34f572b 100644
--- a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
+++ b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
@@ -256,6 +256,49 @@
               new DeserializationEnvironment(null)..add("x^0", x),
               component.root));
     }(),
+    () {
+      Constructor constructor =
+          new Constructor(new FunctionNode(null), name: new Name("foo"));
+      Class klass =
+          new Class(name: "A", constructors: <Constructor>[constructor]);
+      Library library = new Library(
+          new Uri(scheme: "package", path: "foo/bar.dart"),
+          classes: <Class>[klass]);
+      Component component = new Component(libraries: <Library>[library]);
+      component.computeCanonicalNames();
+      return new TestCase(
+          name: "/* suppose A {A.foo();} */ new A()",
+          node: new ConstructorInvocation.byReference(
+              constructor.reference, new Arguments([])),
+          expectation: ""
+              "(invoke-constructor"
+              " \"package:foo/bar.dart::A::@constructors::foo\""
+              " () () ())",
+          serializationState: new SerializationState(null),
+          deserializationState: new DeserializationState(null, component.root));
+    }(),
+    () {
+      Constructor constructor = new Constructor(new FunctionNode(null),
+          name: new Name("foo"), isConst: true);
+      Class klass =
+          new Class(name: "A", constructors: <Constructor>[constructor]);
+      Library library = new Library(
+          new Uri(scheme: "package", path: "foo/bar.dart"),
+          classes: <Class>[klass]);
+      Component component = new Component(libraries: <Library>[library]);
+      component.computeCanonicalNames();
+      return new TestCase(
+          name: "/* suppose A {const A.foo();} */ const A()",
+          node: new ConstructorInvocation.byReference(
+              constructor.reference, new Arguments([]),
+              isConst: true),
+          expectation: ""
+              "(invoke-const-constructor"
+              " \"package:foo/bar.dart::A::@constructors::foo\""
+              " () () ())",
+          serializationState: new SerializationState(null),
+          deserializationState: new DeserializationState(null, component.root));
+    }(),
   ];
   for (TestCase testCase in tests) {
     String roundTripInput =