Merge branch 'expression-function-as-arg' of https://github.com/a14n/dart_style into a14n-expression-function-as-arg
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fae032d..b765aa4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,24 @@
+# 1.2.7
+
+* Improve indentation of adjacent strings inside `=>` functions.
+
 # 1.2.6
 
 * Properly format trailing commas in assertions.
+* Improve indentation of adjacent strings. This fixes a regression introduced
+  in 1.2.5 and hopefully makes adjacent strings generally look better.
+
+  Adjacent strings in argument lists now format the same regardless of whether
+  the argument list contains a trailing comma. The rule is that if the
+  argument list contains no other strings, then the adjacent strings do not
+  get extra indentation. This keeps them lined up when doing so is unlikely to
+  be confused as showing separate independent string arguments.
+
+  Previously, adjacent strings were never indented in argument lists without a
+  trailing comma and always in argument lists that did. With this change,
+  adjacent strings are still always indented in collection literals because
+  readers are likely to interpret a series of unindented lines there as showing
+  separate collection elements.
 
 # 1.2.5
 
diff --git a/bin/format.dart b/bin/format.dart
index 675fd11..5a70dc4 100644
--- a/bin/format.dart
+++ b/bin/format.dart
@@ -15,7 +15,7 @@
 import 'package:dart_style/src/style_fix.dart';
 
 // Note: The following line of code is modified by tool/grind.dart.
-const version = "1.2.5";
+const version = "1.2.7";
 
 void main(List<String> args) {
   var parser = ArgParser(allowTrailingOptions: true);
diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart
index 4824302..2cf93c4 100644
--- a/lib/src/dart_formatter.dart
+++ b/lib/src/dart_formatter.dart
@@ -6,6 +6,7 @@
 
 import 'dart:math' as math;
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/error/error.dart';
@@ -88,6 +89,12 @@
   SourceCode formatSource(SourceCode source) {
     var errorListener = ErrorListener();
 
+    // Enable all features that are enabled by default in the current analyzer
+    // version.
+    // TODO(paulberry): consider plumbing in experiment enable flags from the
+    // command line.
+    var featureSet = FeatureSet.fromEnableFlags([]);
+
     // Tokenize the source.
     var reader = CharSequenceReader(source.text);
     var stringSource = StringSource(source.text, source.uri);
@@ -111,11 +118,9 @@
     errorListener.throwIfErrors();
 
     // Parse it.
-    var parser = Parser(stringSource, errorListener);
+    var parser = Parser(stringSource, errorListener, featureSet: featureSet);
     parser.enableOptionalNewAndConst = true;
     parser.enableSetLiterals = true;
-    parser.enableSpreadCollections = true;
-    parser.enableControlFlowCollections = true;
 
     AstNode node;
     if (source.isCompilationUnit) {
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index e31aa50..184b4fb 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -186,9 +186,70 @@
   }
 
   visitAdjacentStrings(AdjacentStrings node) {
+    // We generally want to indent adjacent strings because it can be confusing
+    // otherwise when they appear in a list of expressions, like:
+    //
+    //     [
+    //       "one",
+    //       "two"
+    //       "three",
+    //       "four"
+    //     ]
+    //
+    // Especially when these stings are longer, it can be hard to tell that
+    // "three" is a continuation of the previous argument.
+    //
+    // However, the indentation is distracting in argument lists that don't
+    // suffer from this ambiguity:
+    //
+    //     test(
+    //         "A very long test description..."
+    //             "this indentation looks bad.", () { ... });
+    //
+    // To balance these, we omit the indentation when an adjacent string
+    // expression is the only string in an argument list.
+    var shouldNest = true;
+
+    var parent = node.parent;
+    if (parent is ArgumentList) {
+      shouldNest = false;
+
+      for (var argument in parent.arguments) {
+        if (argument == node) continue;
+        if (argument is StringLiteral) {
+          shouldNest = true;
+          break;
+        }
+      }
+    } else if (parent is Assertion) {
+      // Treat asserts like argument lists.
+      shouldNest = false;
+      if (parent.condition != node && parent.condition is StringLiteral) {
+        shouldNest = true;
+      }
+
+      if (parent.message != node && parent.message is StringLiteral) {
+        shouldNest = true;
+      }
+    } else if (parent is VariableDeclaration ||
+        parent is AssignmentExpression &&
+            parent.rightHandSide == node &&
+            parent.parent is ExpressionStatement) {
+      // Don't add extra indentation in a variable initializer or assignment:
+      //
+      //     var variable =
+      //         "no extra"
+      //         "indent";
+      shouldNest = false;
+    } else if (parent is NamedExpression || parent is ExpressionFunctionBody) {
+      shouldNest = false;
+    }
+
     builder.startSpan();
     builder.startRule();
+    if (shouldNest) builder.nestExpression();
     visitNodes(node.strings, between: splitOrNewline);
+    if (shouldNest) builder.unnest();
     builder.endRule();
     builder.endSpan();
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index f13b8de..b1d58e5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
 name: dart_style
 # Note: See tool/grind.dart for how to bump the version.
-version: 1.2.6-dev
+version: 1.2.8-dev
 author: Dart Team <misc@dartlang.org>
 description: >-
   Opinionated, automatic Dart source code formatter.
@@ -11,7 +11,7 @@
   sdk: '>=2.1.0 <3.0.0'
 
 dependencies:
-  analyzer: '>=0.36.0 <0.37.0'
+  analyzer: '>=0.36.3 <0.37.0'
   args: '>=0.12.1 <2.0.0'
   path: ^1.0.0
   source_span: ^1.4.0
diff --git a/test/regression/0100/0185.stmt b/test/regression/0100/0185.stmt
index aac3da2..29a2b7a 100644
--- a/test/regression/0100/0185.stmt
+++ b/test/regression/0100/0185.stmt
@@ -9,6 +9,6 @@
 const NO_DART_SCRIPT_AND_EXPERIMENTAL = const MessageTemplate(
     const MessageId('polymer', 6),
     'The experimental bootstrap feature doesn\'t support script tags on '
-    'the main document (for now).',
+        'the main document (for now).',
     'Script tags with experimental bootstrap',
     'This experimental feature is no longer supported.');
\ No newline at end of file
diff --git a/test/regression/0200/0211.unit b/test/regression/0200/0211.unit
index 01766d8..aad9674 100644
--- a/test/regression/0200/0211.unit
+++ b/test/regression/0200/0211.unit
@@ -24,7 +24,7 @@
   JS(
       'void',
       'Object.defineProperty(#, #, '
-      '{value: #, enumerable: false, writable: true, configurable: true})',
+          '{value: #, enumerable: false, writable: true, configurable: true})',
       obj,
       property,
       value);
diff --git a/test/regression/0700/0705.stmt b/test/regression/0700/0705.stmt
new file mode 100644
index 0000000..38f2fd2
--- /dev/null
+++ b/test/regression/0700/0705.stmt
@@ -0,0 +1,10 @@
+>>>
+final _appUrl = Platform.isIOS
+    ? 'https://itunes.apple.com/us/app/google-adwords/id1037457231'
+    : 'https://play.google.com/store/apps/details?id=com.google.android.apps.'
+    'adwords';
+<<<
+final _appUrl = Platform.isIOS
+    ? 'https://itunes.apple.com/us/app/google-adwords/id1037457231'
+    : 'https://play.google.com/store/apps/details?id=com.google.android.apps.'
+        'adwords';
\ No newline at end of file
diff --git a/test/regression/0700/0799.unit b/test/regression/0700/0799.unit
new file mode 100644
index 0000000..acd54a4
--- /dev/null
+++ b/test/regression/0700/0799.unit
@@ -0,0 +1,14 @@
+>>>
+@ShouldThrow(
+  'Could not generate `toJson` code for `watch`.\n'
+  'None of the provided `TypeHelper` instances support the defined type.',
+  configurations: ['default'],
+)
+class C {}
+<<<
+@ShouldThrow(
+  'Could not generate `toJson` code for `watch`.\n'
+  'None of the provided `TypeHelper` instances support the defined type.',
+  configurations: ['default'],
+)
+class C {}
\ No newline at end of file
diff --git a/test/regression/0800/0802.unit b/test/regression/0800/0802.unit
new file mode 100644
index 0000000..6e7323e
--- /dev/null
+++ b/test/regression/0800/0802.unit
@@ -0,0 +1,24 @@
+>>>
+class C {
+  @override
+  String get message =>
+      'Unrecognized keys: [${unrecognizedKeys.join(', ')}]; supported keys: '
+          '[${allowedKeys.join(', ')}]';
+}
+<<<
+class C {
+  @override
+  String get message =>
+      'Unrecognized keys: [${unrecognizedKeys.join(', ')}]; supported keys: '
+      '[${allowedKeys.join(', ')}]';
+}
+>>>
+String _link(String version, String owner, String name) =>
+    '${_anchorUriForName(owner, name)}: '
+        'https://pub.dartlang.org/documentation/json_annotation/$version/'
+        'json_annotation/$owner/$name.html';
+<<<
+String _link(String version, String owner, String name) =>
+    '${_anchorUriForName(owner, name)}: '
+    'https://pub.dartlang.org/documentation/json_annotation/$version/'
+    'json_annotation/$owner/$name.html';
\ No newline at end of file
diff --git a/test/regression/other/flutter.unit b/test/regression/other/flutter.unit
new file mode 100644
index 0000000..98dbde8
--- /dev/null
+++ b/test/regression/other/flutter.unit
@@ -0,0 +1,18 @@
+>>>
+const Vendor _trevor = Vendor(
+    name: 'Trevor’s shop',
+    avatarAsset: 'people/square/trevor.png',
+    avatarAssetPackage: _kGalleryAssetsPackage,
+    description:
+        'Trevor makes great stuff for awesome people like you. Super cool and extra '
+            'awesome all of his shop’s goods are handmade with love. Custom orders are '
+            'available upon request if you need something extra special.');
+<<<
+const Vendor _trevor = Vendor(
+    name: 'Trevor’s shop',
+    avatarAsset: 'people/square/trevor.png',
+    avatarAssetPackage: _kGalleryAssetsPackage,
+    description:
+        'Trevor makes great stuff for awesome people like you. Super cool and extra '
+        'awesome all of his shop’s goods are handmade with love. Custom orders are '
+        'available upon request if you need something extra special.');
\ No newline at end of file
diff --git a/test/whitespace/adjacent_strings.stmt b/test/whitespace/adjacent_strings.stmt
new file mode 100644
index 0000000..b368189
--- /dev/null
+++ b/test/whitespace/adjacent_strings.stmt
@@ -0,0 +1,258 @@
+40 columns                              |
+>>> do not indent adjacent strings if other args are not strings
+function(
+    notString,
+    "adjacent"
+    "string");
+<<<
+function(
+    notString,
+    "adjacent"
+    "string");
+>>> do not indent adjacent strings if other args are not strings
+function(
+    notString,
+    "adjacent"
+    "string",);
+<<<
+function(
+  notString,
+  "adjacent"
+  "string",
+);
+>>> do indent adjacent strings if other arg is string
+function(
+    "string",
+    notString,
+    "adjacent"
+    "string");
+<<<
+function(
+    "string",
+    notString,
+    "adjacent"
+        "string");
+>>> do indent adjacent strings if other arg is string
+function(
+    "string",
+    notString,
+    "adjacent"
+    "string",);
+<<<
+function(
+  "string",
+  notString,
+  "adjacent"
+      "string",
+);
+>>> do indent adjacent strings if other arg is string interpolation
+function(
+    "${str}${ing}",
+    notString,
+    "adjacent"
+    "string");
+<<<
+function(
+    "${str}${ing}",
+    notString,
+    "adjacent"
+        "string");
+>>> do indent adjacent strings if other arg is adjacent string
+function(
+    "adjacent"
+    "string",
+    notString,
+    "adjacent"
+    "string");
+<<<
+function(
+    "adjacent"
+        "string",
+    notString,
+    "adjacent"
+        "string");
+>>> always indent adjacent strings in list
+var list = [
+  "adjacent"
+  "string",
+  "another"
+  "adjacent"
+  "string"
+];
+<<<
+var list = [
+  "adjacent"
+      "string",
+  "another"
+      "adjacent"
+      "string"
+];
+>>> always indent adjacent strings in map key
+var map = {
+  "adjacent"
+  "string": value,
+  "another"
+  "adjacent"
+  "string": value
+};
+<<<
+var map = {
+  "adjacent"
+      "string": value,
+  "another"
+      "adjacent"
+      "string": value
+};
+>>> always indent adjacent strings in map value
+var map = {
+  key: "adjacent"
+  "string",
+  key: "another"
+  "adjacent"
+  "string"
+};
+<<<
+var map = {
+  key: "adjacent"
+      "string",
+  key: "another"
+      "adjacent"
+      "string"
+};
+>>> always indent adjacent strings in set
+var set = {
+  "adjacent"
+  "string",
+  "another"
+  "adjacent"
+  "string"
+};
+<<<
+var set = {
+  "adjacent"
+      "string",
+  "another"
+      "adjacent"
+      "string"
+};
+>>> don't indent in => body
+main() => "adjacent"
+"string"
+"another";
+<<<
+main() => "adjacent"
+    "string"
+    "another";
+>>> don't indent in long => body
+main() => "very very very very long adjacent"
+"string"
+"another";
+<<<
+main() =>
+    "very very very very long adjacent"
+    "string"
+    "another";
+>>> don't indent in => lambda
+function(
+  (parameter) => "string"
+  "adjacent",
+  (parameter) => "long long long long string"
+  "adjacent",
+  another);
+<<<
+function(
+    (parameter) => "string"
+        "adjacent",
+    (parameter) =>
+        "long long long long string"
+        "adjacent",
+    another);
+>>> indent in then branch of ?:
+var string = c ? "adjacent"
+"string" : "other";
+<<<
+var string = c
+    ? "adjacent"
+        "string"
+    : "other";
+>>> indent in else branch of ?:
+var string = c ? "other" : "adjacent"
+"string";
+<<<
+var string = c
+    ? "other"
+    : "adjacent"
+        "string";
+>>> don't indent in initializer
+var longVariableName = "very long adjacent"
+"string";
+<<<
+var longVariableName =
+    "very long adjacent"
+    "string";
+>>> don't indent assignment in statement position
+long.receiver.expression = "very long adjacent"
+"string";
+<<<
+long.receiver.expression =
+    "very long adjacent"
+    "string";
+>>> string interpolation counts as a string
+function(
+    "adjacent"
+    "string",
+    "${str}${ing}");
+<<<
+function(
+    "adjacent"
+        "string",
+    "${str}${ing}");
+>>> another adjacent string counts as a string
+function(
+    "adjacent"
+    "string",
+    "another"
+    "adjacent");
+<<<
+function(
+    "adjacent"
+        "string",
+    "another"
+        "adjacent");
+>>> do not indent adjacent strings in assert if other args are not strings
+assert(
+    condition,
+    "adjacent"
+    "string");
+<<<
+assert(
+    condition,
+    "adjacent"
+    "string");
+>>> don't need extra indentation inside named arguments
+function(named: "adjacent"
+"string",
+another: "adjacent"
+"string"
+"more");
+<<<
+function(
+    named: "adjacent"
+        "string",
+    another: "adjacent"
+        "string"
+        "more");
+>>> don't need extra indentation inside named arguments
+function(named: "adjacent"
+"string",
+another: "adjacent"
+"string"
+"more",);
+<<<
+function(
+  named: "adjacent"
+      "string",
+  another: "adjacent"
+      "string"
+      "more",
+);
\ No newline at end of file