[kernel] Add ability to (de)serialize DirectMethodInvocation

Change-Id: I52371f85a76cf7c7422365052b248229a22a9287
Reviewed-on: https://dart-review.googlesource.com/c/89529
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Daniel Hillerström <hillerstrom@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 55a3b2a..e6f6503 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -105,6 +105,10 @@
   String visitStaticInvocation(StaticInvocation expression) {
     return expression.isConst ? "invoke-const-static" : "invoke-static";
   }
+
+  String visitDirectMethodInvocation(DirectMethodInvocation _) {
+    return "invoke-direct-method";
+  }
 }
 
 TextSerializer<InvalidExpression> invalidExpressionSerializer = new Wrapped(
@@ -641,6 +645,25 @@
       isConst: true);
 }
 
+TextSerializer<DirectMethodInvocation> directMethodInvocationSerializer =
+    new Wrapped(
+        unwrapDirectMethodInvocation,
+        wrapDirectMethodInvocation,
+        new Tuple3Serializer(expressionSerializer,
+            const CanonicalNameSerializer(), argumentsSerializer));
+
+Tuple3<Expression, CanonicalName, Arguments> unwrapDirectMethodInvocation(
+    DirectMethodInvocation expression) {
+  return new Tuple3(expression.receiver,
+      expression.targetReference.canonicalName, expression.arguments);
+}
+
+DirectMethodInvocation wrapDirectMethodInvocation(
+    Tuple3<Expression, CanonicalName, Arguments> tuple) {
+  return new DirectMethodInvocation.byReference(
+      tuple.first, tuple.second.getReference(), tuple.third);
+}
+
 Case<Expression> expressionSerializer =
     new Case.uninitialized(const ExpressionTagger());
 
@@ -853,6 +876,7 @@
     "set-direct-prop",
     "invoke-static",
     "invoke-const-static",
+    "invoke-direct-method",
   ]);
   expressionSerializer.serializers.addAll([
     stringLiteralSerializer,
@@ -895,6 +919,7 @@
     directPropertySetSerializer,
     staticInvocationSerializer,
     constStaticInvocationSerializer,
+    directMethodInvocationSerializer,
   ]);
   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 d8c33d4..0976525 100644
--- a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
+++ b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
@@ -229,6 +229,33 @@
               new DeserializationEnvironment(null)..add("x^0", x),
               component.root));
     }(),
+    () {
+      Procedure method = new Procedure(
+          new Name("foo"), ProcedureKind.Method, new FunctionNode(null),
+          isStatic: true, isConst: true);
+      Class klass = new Class(name: "A", procedures: <Procedure>[method]);
+      Library library = new Library(
+          new Uri(scheme: "package", path: "foo/bar.dart"),
+          classes: <Class>[klass]);
+      Component component = new Component(libraries: <Library>[library]);
+      component.computeCanonicalNames();
+
+      VariableDeclaration x =
+          new VariableDeclaration("x", type: const DynamicType());
+      return new TestCase(
+          name: "/* suppose A {foo() {...}} A x; */ x.{A::foo}()",
+          node: new DirectMethodInvocation.byReference(
+              new VariableGet(x), method.reference, new Arguments([])),
+          expectation: ""
+              "(invoke-direct-method (get-var \"x^0\" _)"
+              " \"package:foo/bar.dart::A::@methods::foo\""
+              " () () ())",
+          serializationState: new SerializationState(
+              new SerializationEnvironment(null)..add(x, "x^0")),
+          deserializationState: new DeserializationState(
+              new DeserializationEnvironment(null)..add("x^0", x),
+              component.root));
+    }(),
   ];
   for (TestCase testCase in tests) {
     String roundTripInput =