Work in progress support for formatting extension methods.
diff --git a/example/format.dart b/example/format.dart
index 6edbfe0..3b00c91 100644
--- a/example/format.dart
+++ b/example/format.dart
@@ -13,16 +13,18 @@
 import 'package:dart_style/src/debug.dart' as debug;
 
 void main(List<String> args) {
-  // Enable debugging so you can see some of the formatter's internal state.
-  // Normal users do not do this.
-  debug.traceChunkBuilder = true;
-  debug.traceLineWriter = true;
-  debug.traceSplitter = true;
-  debug.useAnsiColors = true;
-
-  runTest("regression/0000/0068.stmt", 14);
-
-  formatStmt("hello(world);");
+  formatUnit("""
+extension A on B {
+  var a = 1;
+  b() {}
+  c() => null;
+  get d {}
+  get e => null;
+  set f(value) {}
+  set g(value) => null;
+  var h = 1;
+}
+""");
 }
 
 void formatStmt(String source, [int pageWidth = 80]) {
diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart
index 478e6a7..fe0c1ca 100644
--- a/lib/src/dart_formatter.dart
+++ b/lib/src/dart_formatter.dart
@@ -93,12 +93,16 @@
     // version.
     // TODO(paulberry): consider plumbing in experiment enable flags from the
     // command line.
-    var featureSet = FeatureSet.fromEnableFlags(["non-nullable"]);
+    var featureSet = FeatureSet.fromEnableFlags([
+      "extension-methods",
+      "non-nullable",
+    ]);
 
     // Tokenize the source.
     var reader = CharSequenceReader(source.text);
     var stringSource = StringSource(source.text, source.uri);
     var scanner = Scanner(stringSource, reader, errorListener);
+    scanner.configureFeatures(featureSet);
     var startToken = scanner.tokenize();
     var lineInfo = LineInfo(scanner.lineStarts);
 
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index fb2f231..7106569 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -1145,6 +1145,26 @@
     visit(node.superclass);
   }
 
+  void visitExtensionDeclaration(ExtensionDeclaration node) {
+    visitMetadata(node.metadata);
+
+    builder.nestExpression();
+    token(node.extensionKeyword);
+    space();
+    visit(node.name);
+    visit(node.typeParameters);
+    space();
+    token(node.onKeyword);
+    space();
+    visit(node.extendedType);
+    space();
+    builder.unnest();
+
+    _beginBody(node.leftBracket);
+    _visitMembers(node.members);
+    _endBody(node.rightBracket);
+  }
+
   visitFieldDeclaration(FieldDeclaration node) {
     visitMetadata(node.metadata);
 
diff --git a/pubspec.lock b/pubspec.lock
index d4d3620..b53d5f0 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -7,7 +7,7 @@
       name: analyzer
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.38.0"
+    version: "0.38.1"
   archive:
     dependency: transitive
     description:
@@ -70,7 +70,7 @@
       name: crypto
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.1+1"
+    version: "2.1.2"
   csslib:
     dependency: transitive
     description:
@@ -84,7 +84,7 @@
       name: front_end
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.1.22"
+    version: "0.1.23"
   glob:
     dependency: transitive
     description:
@@ -147,7 +147,7 @@
       name: kernel
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.22"
+    version: "0.3.23"
   matcher:
     dependency: transitive
     description:
@@ -350,7 +350,7 @@
       name: vm_service
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.1.1"
   watcher:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 6c4c50a..fc607c1 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.10
+version: 1.3.0-dev
 author: Dart Team <misc@dartlang.org>
 description: >-
   Opinionated, automatic Dart source code formatter.
@@ -11,7 +11,7 @@
   sdk: '>=2.3.0 <3.0.0'
 
 dependencies:
-  analyzer: '>=0.37.0 <0.39.0'
+  analyzer: '>=0.38.0 <0.39.0'
   args: '>=0.12.1 <2.0.0'
   path: ^1.0.0
   source_span: ^1.4.0
diff --git a/test/comments/extensions.unit b/test/comments/extensions.unit
new file mode 100644
index 0000000..b6f3c13
--- /dev/null
+++ b/test/comments/extensions.unit
@@ -0,0 +1,182 @@
+40 columns                              |
+>>> indented line comment
+extension A on B {
+  // comment
+}
+<<<
+extension A on B {
+  // comment
+}
+>>> line comment on opening line
+extension A on B { // comment
+}
+<<<
+extension A on B {
+  // comment
+}
+>>> indented block comment
+extension A on B {
+  /* comment */
+}
+<<<
+extension A on B {
+  /* comment */
+}
+>>> block comment with trailing newline
+extension A on B {/* comment */
+}
+<<<
+extension A on B {
+  /* comment */
+}
+>>> block comment with leading newline
+extension A on B {
+  /* comment */}
+<<<
+extension A on B {
+  /* comment */
+}
+>>> inline block comment
+extension A on B {  /* comment */  }
+<<<
+extension A on B {/* comment */}
+>>> multiple comments on opening line
+extension A on B { /* first */ // second
+}
+<<<
+extension A on B {
+  /* first */ // second
+}
+>>> multiple inline block comments
+extension A on B {  /* 1 */   /* 2 */   /* 3 */  }
+<<<
+extension A on B {/* 1 */ /* 2 */ /* 3 */}
+>>> multiline trailing block comment
+extension A on B {  /* comment
+*/  }
+<<<
+extension A on B {
+  /* comment
+*/
+}
+>>> lines comments at the start of the line in body
+extension A on B {
+//  int a;
+//  int b;
+  int c;
+}
+<<<
+extension A on B {
+//  int a;
+//  int b;
+  int c;
+}
+>>> block comment
+extension A on B/* is cool */{
+  /* int */ foo(/* comment */) => 42;
+}
+<<<
+extension A on B /* is cool */ {
+  /* int */ foo(/* comment */) => 42;
+}
+>>> block comments in odd places
+extension/*1*/A/*2*/on/*3*/B/*4*/{}
+<<<
+extension /*1*/ A /*2*/ on /*3*/ B /*4*/ {}
+>>> line comments in odd places
+extension// 1
+A// 2
+on// 3
+B// 4
+{}
+<<<
+extension // 1
+    A // 2
+    on // 3
+    B // 4
+{}
+>>> block comment
+library foo;
+/* A long
+ * Comment
+*/
+extension A on B /* is cool */ {
+  /* int */ foo() => 42;
+}
+<<<
+library foo;
+
+/* A long
+ * Comment
+*/
+extension A on B /* is cool */ {
+  /* int */ foo() => 42;
+}
+>>> ensure blank line above doc comments
+extension A on B {var a = 1;
+/// doc
+var b = 2;}
+<<<
+extension A on B {
+  var a = 1;
+
+  /// doc
+  var b = 2;
+}
+>>> remove blank line before beginning of body
+extension A on B {
+
+
+
+  // comment
+}
+<<<
+extension A on B {
+  // comment
+}
+>>> nested flush left comment
+extension A on B {
+  method() {
+// flush
+  }
+}
+<<<
+extension A on B {
+  method() {
+// flush
+  }
+}
+>>> nested flush left after non-nested
+extension A on B {
+  method() {
+    // ...
+// flush
+  }
+}
+<<<
+extension A on B {
+  method() {
+    // ...
+// flush
+  }
+}
+>>> force doc comment between extensions to have two newlines before
+extension A on B {} /**
+*/
+extension A on B {}
+<<<
+extension A on B {}
+
+/**
+*/
+extension A on B {}
+>>> force doc comment between classes to have newline after
+extension A on B {}
+/**
+*/ extension A on B {}
+<<<
+extension A on B {}
+
+/**
+*/
+extension A on B {}
\ No newline at end of file
diff --git a/test/whitespace/extensions.unit b/test/whitespace/extensions.unit
new file mode 100644
index 0000000..062e268
--- /dev/null
+++ b/test/whitespace/extensions.unit
@@ -0,0 +1,102 @@
+40 columns                              |
+>>> indentation
+extension A on B {
+var z;
+inc(int x) => ++x;
+foo(int x) {
+if (x == 0) {
+return true;
+}}}
+<<<
+extension A on B {
+  var z;
+  inc(int x) => ++x;
+  foo(int x) {
+    if (x == 0) {
+      return true;
+    }
+  }
+}
+>>> trailing space inside body
+extension A on B {
+  }
+<<<
+extension A on B {}
+>>> leading space before "extension"
+  extension A on B {
+}
+<<<
+extension A on B {}
+>>>
+extension A on B  { int meaningOfLife() => 42; }
+<<<
+extension A on B {
+  int meaningOfLife() => 42;
+}
+>>>
+extension     A      on      B    {
+  }
+<<<
+extension A on B {}
+>>>
+extension A on B{var z;inc(int x) => ++x;}
+<<<
+extension A on B {
+  var z;
+  inc(int x) => ++x;
+}
+>>> eats newlines
+extension
+
+A
+
+
+on
+
+
+B
+
+
+
+{}
+<<<
+extension A on B {}
+>>> require blank line after non-empty block-bodied members
+extension A on B {
+var a = 1; b() {;} c() => null; get d {;} get e => null; set f(value) {;
+} set g(value) => null; var h = 1;}
+<<<
+extension A on B {
+  var a = 1;
+  b() {
+    ;
+  }
+
+  c() => null;
+  get d {
+    ;
+  }
+
+  get e => null;
+  set f(value) {
+    ;
+  }
+
+  set g(value) => null;
+  var h = 1;
+}
+>>> no required blank line after empty block-bodied members
+extension A on B {
+var a = 1; b() {} c() => null; get d {} get e => null; set f(value) {
+} set g(value) => null; var h = 1;}
+<<<
+extension A on B {
+  var a = 1;
+  b() {}
+  c() => null;
+  get d {}
+  get e => null;
+  set f(value) {}
+  set g(value) => null;
+  var h = 1;
+}
\ No newline at end of file