[kernel] Add ability to (de)serialize DirectPropertySet

Change-Id: I769941faa7b80eddb5a9c52f250191dca6c9ecd3
Reviewed-on: https://dart-review.googlesource.com/c/89527
Reviewed-by: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Daniel Hillerström <hillerstrom@google.com>
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index f560fba..6dbc02a 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -101,6 +101,7 @@
   String visitStaticGet(StaticGet _) => "get-static";
   String visitStaticSet(StaticSet _) => "set-static";
   String visitDirectPropertyGet(DirectPropertyGet _) => "get-direct-prop";
+  String visitDirectPropertySet(DirectPropertySet _) => "set-direct-prop";
 }
 
 TextSerializer<InvalidExpression> invalidExpressionSerializer = new Wrapped(
@@ -590,6 +591,24 @@
       tuple.first, tuple.second.getReference());
 }
 
+TextSerializer<DirectPropertySet> directPropertySetSerializer = new Wrapped(
+    unwrapDirectPropertySet,
+    wrapDirectPropertySet,
+    new Tuple3Serializer(expressionSerializer, const CanonicalNameSerializer(),
+        expressionSerializer));
+
+Tuple3<Expression, CanonicalName, Expression> unwrapDirectPropertySet(
+    DirectPropertySet expression) {
+  return new Tuple3(expression.receiver,
+      expression.targetReference.canonicalName, expression.value);
+}
+
+DirectPropertySet wrapDirectPropertySet(
+    Tuple3<Expression, CanonicalName, Expression> tuple) {
+  return new DirectPropertySet.byReference(
+      tuple.first, tuple.second.getReference(), tuple.third);
+}
+
 Case<Expression> expressionSerializer =
     new Case.uninitialized(const ExpressionTagger());
 
@@ -799,6 +818,7 @@
     "get-static",
     "set-static",
     "get-direct-prop",
+    "set-direct-prop",
   ]);
   expressionSerializer.serializers.addAll([
     stringLiteralSerializer,
@@ -838,6 +858,7 @@
     staticGetSerializer,
     staticSetSerializer,
     directPropertyGetSerializer,
+    directPropertySetSerializer,
   ]);
   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 2864bf2..6d31963 100644
--- a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
+++ b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
@@ -156,6 +156,30 @@
               new DeserializationEnvironment(null)..add("x^0", x),
               component.root));
     }(),
+    () {
+      Field field = new Field(new Name("field"), type: const DynamicType());
+      Class klass = new Class(name: "A", fields: <Field>[field]);
+      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 {dynamic field;} A x; */ x.{A::field} = 42",
+          node: new DirectPropertySet.byReference(
+              new VariableGet(x), field.reference, new IntLiteral(42)),
+          expectation: ""
+              "(set-direct-prop (get-var \"x^0\" _)"
+              " \"package:foo/bar.dart::A::@fields::field\" (int 42))",
+          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 =