Preserve type arguments in generic invocation expressions.

Fix #621.

It already handled generic *method* invocations like "foo<int>(1)".
This fixes cases where the receiver is itself an expression, like
"(<T>(T t) => t)<int>(1)".

R=kevmoo@google.com

Review-Url: https://codereview.chromium.org//2844573002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58bbc3a..d71f499 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,9 @@
 # 1.0.4-dev
+
 * Ensure formatter throws an exception instead of introducing non-whitespace
-  changes.
+  changes. This sanity check ensures the formatter does not erase user code
+  when the formatter itself contains a bug.
+* Preserve type arguments in function expression invocations (#621).
 
 # 1.0.3
 
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index 213f7a4..f78627e 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -1151,8 +1151,16 @@
   }
 
   visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+    // Try to keep the entire invocation one line.
+    builder.startSpan();
+    builder.nestExpression();
+
     visit(node.function);
-    visit(node.argumentList);
+    visit(node.typeArguments);
+    visitArgumentList(node.argumentList, nestExpression: false);
+
+    builder.unnest();
+    builder.endSpan();
   }
 
   visitFunctionTypeAlias(FunctionTypeAlias node) {
diff --git a/test/regression/0600/0621.stmt b/test/regression/0600/0621.stmt
new file mode 100644
index 0000000..08cb930
--- /dev/null
+++ b/test/regression/0600/0621.stmt
@@ -0,0 +1,8 @@
+>>>
+var x = (f as dynamic)<int>(40, 2);
+<<<
+var x = (f as dynamic)<int>(40, 2);
+>>>
+var y = (f as dynamic)<String>('hi', '!');
+<<<
+var y = (f as dynamic)<String>('hi', '!');
\ No newline at end of file
diff --git a/test/splitting/type_arguments.stmt b/test/splitting/type_arguments.stmt
index 2ba351a..9675153 100644
--- a/test/splitting/type_arguments.stmt
+++ b/test/splitting/type_arguments.stmt
@@ -65,4 +65,33 @@
 {
   <int>[];
   <int>[];
-}
\ No newline at end of file
+}
+>>> type arguments on invocation expressions, all on one line
+(fn)<T, S>(1, 2);
+<<<
+(fn)<T, S>(1, 2);
+>>> type arguments on invocation, prefer to not split at type args
+(longFunction)<TypeArgument>(valueArgument);
+<<<
+(longFunction)<TypeArgument>(
+    valueArgument);
+>>> type arguments on invocation expressions split both type and value arguments
+(longFunction)<First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth>(first, second, third, fourth, fifth, sixth, seventh, eighth);
+<<<
+(longFunction)<
+        First,
+        Second,
+        Third,
+        Fourth,
+        Fifth,
+        Sixth,
+        Seventh,
+        Eighth>(
+    first,
+    second,
+    third,
+    fourth,
+    fifth,
+    sixth,
+    seventh,
+    eighth);
\ No newline at end of file