Merge pull request #947 from dart-lang/external-abstract-variables

Format `external` and `abstract` on variables.
diff --git a/.travis.yml b/.travis.yml
index 1785982..29d4769 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,8 @@
 language: dart
 
 dart:
-  - 2.7.0
+#  - 2.10.0
+# Disabling stable for now since we rely on a null safety version of test.
   - dev
 
 dart_task:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a865194..ae83093 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 * Split help into verbose and non-verbose lists (#938).
 * Don't crash when non-ASCII whitespace is trimmed (#901).
 * Split all conditional expressions (`?:`) when they are nested (#927).
+* Handle `external` and `abstract` fields and variables (#946).
 
 # 1.3.6
 
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index 04a2bee..1f63c6c 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -1425,7 +1425,9 @@
     visitMetadata(node.metadata);
 
     _simpleStatement(node, () {
+      modifier(node.externalKeyword);
       modifier(node.staticKeyword);
+      modifier(node.abstractKeyword);
       modifier(node.covariantKeyword);
       visit(node.fields);
     });
@@ -2613,6 +2615,7 @@
     visitMetadata(node.metadata);
 
     _simpleStatement(node, () {
+      modifier(node.externalKeyword);
       visit(node.variables);
     });
   }
diff --git a/pubspec.lock b/pubspec.lock
index eea1964..ee29188 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -7,14 +7,14 @@
       name: _fe_analyzer_shared
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "8.0.0"
   analyzer:
     dependency: "direct main"
     description:
       name: analyzer
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.39.5"
+    version: "0.40.0"
   archive:
     dependency: transitive
     description:
@@ -35,35 +35,35 @@
       name: async
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.4.1"
+    version: "2.5.0-nullsafety"
   boolean_selector:
     dependency: transitive
     description:
       name: boolean_selector
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.1.0-nullsafety"
   charcode:
     dependency: transitive
     description:
       name: charcode
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.3"
+    version: "1.2.0-nullsafety"
   cli_util:
     dependency: transitive
     description:
       name: cli_util
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.1.3+2"
+    version: "0.2.0"
   collection:
     dependency: transitive
     description:
       name: collection
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.14.12"
+    version: "1.15.0-nullsafety.2"
   convert:
     dependency: transitive
     description:
@@ -77,21 +77,21 @@
       name: coverage
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.13.9"
+    version: "0.14.0"
   crypto:
     dependency: transitive
     description:
       name: crypto
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.4"
+    version: "2.1.5"
   csslib:
     dependency: transitive
     description:
       name: csslib
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.16.1"
+    version: "0.16.2"
   glob:
     dependency: transitive
     description:
@@ -105,7 +105,7 @@
       name: grinder
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.8.4"
+    version: "0.8.5"
   html:
     dependency: transitive
     description:
@@ -119,7 +119,7 @@
       name: http
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.12.0+4"
+    version: "0.12.2"
   http_multi_server:
     dependency: transitive
     description:
@@ -147,7 +147,7 @@
       name: js
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.6.1+1"
+    version: "0.6.3-nullsafety"
   logging:
     dependency: transitive
     description:
@@ -161,49 +161,42 @@
       name: matcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.12.6"
+    version: "0.12.10-nullsafety"
   meta:
     dependency: transitive
     description:
       name: meta
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.8"
+    version: "1.3.0-nullsafety.2"
   mime:
     dependency: transitive
     description:
       name: mime
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.9.6+3"
-  multi_server_socket:
-    dependency: transitive
-    description:
-      name: multi_server_socket
-      url: "https://pub.dartlang.org"
-    source: hosted
-    version: "1.0.2"
+    version: "0.9.7"
   node_interop:
     dependency: transitive
     description:
       name: node_interop
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.3"
+    version: "1.1.1"
   node_io:
     dependency: transitive
     description:
       name: node_io
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.1+2"
+    version: "1.1.1"
   node_preamble:
     dependency: "direct dev"
     description:
       name: node_preamble
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.4.8"
+    version: "1.4.12"
   package_config:
     dependency: transitive
     description:
@@ -217,21 +210,21 @@
       name: path
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.6.4"
+    version: "1.8.0-nullsafety"
   pedantic:
     dependency: "direct dev"
     description:
       name: pedantic
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.9.0"
+    version: "1.10.0-nullsafety"
   pool:
     dependency: transitive
     description:
       name: pool
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.4.0"
+    version: "1.5.0-nullsafety"
   pub_semver:
     dependency: "direct dev"
     description:
@@ -245,7 +238,7 @@
       name: shelf
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.7.5"
+    version: "0.7.9"
   shelf_packages_handler:
     dependency: transitive
     description:
@@ -273,70 +266,70 @@
       name: source_map_stack_trace
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.1.0-nullsafety.1"
   source_maps:
     dependency: transitive
     description:
       name: source_maps
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.10.9"
+    version: "0.10.10-nullsafety"
   source_span:
     dependency: "direct main"
     description:
       name: source_span
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.7.0"
+    version: "1.8.0-nullsafety"
   stack_trace:
     dependency: transitive
     description:
       name: stack_trace
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.9.3"
+    version: "1.10.0-nullsafety"
   stream_channel:
     dependency: transitive
     description:
       name: stream_channel
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.1.0-nullsafety"
   string_scanner:
     dependency: transitive
     description:
       name: string_scanner
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.5"
+    version: "1.1.0-nullsafety"
   term_glyph:
     dependency: transitive
     description:
       name: term_glyph
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.2.0-nullsafety"
   test:
     dependency: "direct dev"
     description:
       name: test
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.14.2"
+    version: "1.16.0-nullsafety.2"
   test_api:
     dependency: transitive
     description:
       name: test_api
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.15"
+    version: "0.2.19-nullsafety"
   test_core:
     dependency: transitive
     description:
       name: test_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.3"
+    version: "0.3.12-nullsafety.2"
   test_descriptor:
     dependency: "direct dev"
     description:
@@ -357,21 +350,21 @@
       name: typed_data
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.6"
+    version: "1.3.0-nullsafety.2"
   vm_service:
     dependency: transitive
     description:
       name: vm_service
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.0.0"
+    version: "4.2.0"
   watcher:
     dependency: transitive
     description:
       name: watcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.9.7+14"
+    version: "0.9.7+15"
   web_socket_channel:
     dependency: transitive
     description:
@@ -385,13 +378,13 @@
       name: webkit_inspection_protocol
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.5.0+1"
+    version: "0.7.3"
   yaml:
     dependency: "direct dev"
     description:
       name: yaml
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.2.0"
+    version: "2.2.1"
 sdks:
-  dart: ">=2.7.0 <3.0.0"
+  dart: ">=2.10.0-0 <2.10.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 3d8b8ed..b28993f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,10 +7,10 @@
 homepage: https://github.com/dart-lang/dart_style
 
 environment:
-  sdk: '>=2.7.0 <3.0.0'
+  sdk: '>=2.9.0 <3.0.0'
 
 dependencies:
-  analyzer: ">=0.39.5 <0.40.0"
+  analyzer: ^0.40.0
   args: ^1.0.0
   path: ^1.0.0
   source_span: ^1.4.0
@@ -21,7 +21,7 @@
   node_preamble: ^1.0.0
   pedantic: ^1.0.0
   pub_semver: ^1.2.3
-  test: ^1.6.0
+  test: ^1.16.0-nullsafety.2
   test_descriptor: ^1.0.0
   test_process: ^1.0.0
   yaml: ^2.0.0
diff --git a/test/splitting/members.unit b/test/splitting/members.unit
index ecde98f..68af26c 100644
--- a/test/splitting/members.unit
+++ b/test/splitting/members.unit
@@ -26,7 +26,7 @@
   VeryLongTypeAnnotation
       set veryLongSetter(v) {}
 }
->>> do not split after "covariant" in field (at least for now)
+>>> do not split after "covariant" in field
 class Foo {
   covariant var soMuchSoVeryLongFieldNameHere;
   covariant VeryLongTypeAnnotation field;
@@ -37,3 +37,25 @@
   covariant VeryLongTypeAnnotation
       field;
 }
+>>> do not split after "external" in field
+class Foo {
+  external var soMuchSoVeryLongFieldNameHere;
+  external SuperLongTypeAnnotation field;
+}
+<<<
+class Foo {
+  external var soMuchSoVeryLongFieldNameHere;
+  external SuperLongTypeAnnotation
+      field;
+}
+>>> do not split after "abstract" in field
+class Foo {
+  abstract var soMuchSoVeryLongFieldNameHere;
+  abstract SuperLongTypeAnnotation field;
+}
+<<<
+class Foo {
+  abstract var soMuchSoVeryLongFieldNameHere;
+  abstract SuperLongTypeAnnotation
+      field;
+}
\ No newline at end of file
diff --git a/test/whitespace/classes.unit b/test/whitespace/classes.unit
index f306f5a..a4ea79f 100644
--- a/test/whitespace/classes.unit
+++ b/test/whitespace/classes.unit
@@ -144,4 +144,16 @@
   late final int i;
   late int i;
   late var i;
+}
+>>> abstract fields
+class Foo {
+abstract  covariant     var  a  , b   ;
+    abstract    final   int   c;
+  abstract   int i;
+}
+<<<
+class Foo {
+  abstract covariant var a, b;
+  abstract final int c;
+  abstract int i;
 }
\ No newline at end of file
diff --git a/test/whitespace/external.unit b/test/whitespace/external.unit
new file mode 100644
index 0000000..52abb83
--- /dev/null
+++ b/test/whitespace/external.unit
@@ -0,0 +1,45 @@
+40 columns                              |
+>>> top-level function
+ external
+void
+printToConsole(line);
+<<<
+external void printToConsole(line);
+>>> top-level variable
+  external   final   a ,  b  ;
+  external   final    Set < int  >  a ,  b  ;
+  external   var   a  ;
+  external   List < int >   a  ;
+<<<
+external final a, b;
+external final Set<int> a, b;
+external var a;
+external List<int> a;
+>>> static field
+class C {
+  external  static    final   a ,  b  ;
+external    static  final    Set < int  >  a ,  b  ;
+   external   static   var   a  ;
+  external  static    List < int >   a  ;
+}
+<<<
+class C {
+  external static final a, b;
+  external static final Set<int> a, b;
+  external static var a;
+  external static List<int> a;
+}
+>>> instance field
+class C {
+  external   final   a ,  b  ;
+  external   final    Set < String  >  a ,  b  ;
+  external   var   a  ;
+  external   List < int >   a  ;
+}
+<<<
+class C {
+  external final a, b;
+  external final Set<String> a, b;
+  external var a;
+  external List<int> a;
+}
\ No newline at end of file
diff --git a/test/whitespace/functions.unit b/test/whitespace/functions.unit
index f12fbeb..82db3d1 100644
--- a/test/whitespace/functions.unit
+++ b/test/whitespace/functions.unit
@@ -1,10 +1,4 @@
 40 columns                              |
->>> external
- external
-void
-printToConsole(line);
-<<<
-external void printToConsole(line);
 >>> nested functions
 x(){y(){z(){}}}
 <<<
diff --git a/test/whitespace/metadata.unit b/test/whitespace/metadata.unit
index 1168e89..c25e98f 100644
--- a/test/whitespace/metadata.unit
+++ b/test/whitespace/metadata.unit
@@ -354,4 +354,30 @@
     @meta
     late int d;
   }
+}
+>>> on external variable
+@meta  external var x;
+<<<
+@meta
+external var x;
+>>> on external field
+class C {
+  @meta  external static   var  x;
+  @meta  external var x;
+}
+<<<
+class C {
+  @meta
+  external static var x;
+  @meta
+  external var x;
+}
+>>> on abstract field
+class C {
+  @meta  abstract var x;
+}
+<<<
+class C {
+  @meta
+  abstract var x;
 }
\ No newline at end of file