Version 2.1.2-dev.0.0

Merge commit '011a1239fc4c0ed140ddce4773cc791da1936cd4' into dev
diff --git a/.packages b/.packages
index 597ffb9..9d7e756 100644
--- a/.packages
+++ b/.packages
@@ -20,7 +20,6 @@
 boolean_selector:third_party/pkg/boolean_selector/lib
 build_integration:pkg/build_integration/lib
 charcode:third_party/pkg/charcode/lib
-charted:third_party/observatory_pub_packages/packages/charted/lib
 cli_util:third_party/pkg/cli_util/lib
 collection:third_party/pkg/collection/lib
 compiler:pkg/compiler/lib
@@ -36,10 +35,8 @@
 dev_compiler:pkg/dev_compiler/lib
 diagnostic:pkg/diagnostic/lib
 expect:pkg/expect/lib
-file:third_party/pkg/file/packages/file/lib
 fixnum:third_party/pkg/fixnum/lib
 front_end:pkg/front_end/lib
-func:third_party/pkg/func/lib
 gardening:tools/gardening/lib
 glob:third_party/pkg/glob/lib
 html:third_party/pkg/html/lib
@@ -63,22 +60,18 @@
 meta:pkg/meta/lib
 mime:third_party/pkg/mime/lib
 mockito:third_party/pkg/mockito/lib
-mustache4dart:third_party/pkg/mustache4dart/lib
+mustache:third_party/pkg/mustache/lib
 oauth2:third_party/pkg/oauth2/lib
 observatory:runtime/observatory/lib
 package_config:third_party/pkg_tested/package_config/lib
 package_resolver:third_party/pkg_tested/package_resolver/lib
 path:third_party/pkg/path/lib
-petitparser:third_party/pkg/petitparser/lib
-platform:third_party/pkg/platform/lib
 plugin:third_party/pkg/plugin/lib
 pool:third_party/pkg/pool/lib
-process:third_party/pkg/process/lib
 protobuf:third_party/pkg/protobuf/lib
 pub:third_party/pkg/pub/lib
 pub_semver:third_party/pkg/pub_semver/lib
 quiver:third_party/pkg/quiver/lib
-quiver_hashcode:third_party/pkg/quiver_hashcode/lib
 resource:third_party/pkg/resource/lib
 sdk_library_metadata:sdk/lib/_internal/sdk_library_metadata/lib
 shelf:third_party/pkg/shelf/lib
diff --git a/BUILD.gn b/BUILD.gn
index 27a1cf8..ae4c230 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -46,6 +46,7 @@
     "runtime/bin:run_vm_tests",
     "runtime/bin:sample_extension",
     "runtime/bin:test_extension",
+    "runtime/bin:entrypoints_verification_test_extension",
     "runtime/vm:kernel_platform_files($host_toolchain)",
     "utils/kernel-service:kernel-service",
   ]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9db2340..dc9f141 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,111 @@
+## 2.1.2-dev.0.0
+
+* Merge commit 011a1239fc4c0ed140ddce4773cc791da1936cd4 into dev
+
+## 2.1.1
+
+* Identical to 2.1.1-dev.3.2
+
+## 2.1.1-dev.3.2
+
+* Cherry-pick 9d25cc93e850d4717cdc9e1c4bd3623e09c16d47 to dev
+
+## 2.1.1-dev.3.1
+
+* Cherry-pick 46080dd886a622c5520895d49c97506ecedb1df8 to dev
+* Cherry-pick fc62cf037343248c5ace87629d8eb1063f9f2428 to dev
+* Cherry-pick 770ab5275ac34af62d7c39da8eac8c56fdc48edb to dev
+* Cherry-pick 957e194735bda4fcf06cdcc68fa80f3290b17d79 to dev
+
+## 2.1.1-dev.3.0
+
+* Cherry-pick 3cb16d20e7810a2a378bb897d939f67c0b380d88 to dev
+
+## 2.1.1-dev.2.0
+
+### Core library changes
+
+#### `dart:html`
+
+*   Added methods `Element.removeAttribute`, `Element.removeAttributeNS`,
+    `Element.hasAttribute` and `Element.hasAttributeNS`. (Issue [35655][]).
+*   Improved dart2js compilation of `element.attributes.remove(name)` to
+    generate `element.removeAttribute(name)`, so that there is no performance
+    reason to migrate to the above methods.
+*   Fixed a number of `dart:html` P1 bugs:
+
+    *   Fixed HTML API's with callback typedef to correctly convert Dart
+        function to JS function (Issue [35484]).
+    *   HttpStatus constants exposed in `dart:html` (Issue [34318]).
+    *   Expose DomName `ondblclick` and `dblclickEvent` for Angular analyzer.
+    *   Fixed `removeAll` on `classes`; `elements` parameter should be
+        `Iterable<Object>` to match Set's `removeAll` not `Iterable<E>` (Issue
+        [30278]).
+    *   Fixed a number of methods on DataTransferItem, Entry, FileEntry and
+        DirectoryEntry which previously returned NativeJavaScriptObject.  This
+        fixes handling drag/drop of files/directories (Issue [35510]).
+    *   Added ability to allow local file access from Chrome browser in ddb.
+
+[35655]: https://github.com/dart-lang/sdk/issues/35655
+[30278]: https://github.com/dart-lang/sdk/issues/30278
+[34318]: https://github.com/dart-lang/sdk/issues/34318
+[35484]: https://github.com/dart-lang/sdk/issues/35484
+[35510]: https://github.com/dart-lang/sdk/issues/35510
+
+#### `dart:io`
+
+*   Added ability to get and set low level socket options.
+* **Breaking Change:** Adding to a closed `IOSink` now throws a `StateError`.
+
+[29554]: https://github.com/dart-lang/sdk/issues/29554
+
+### Other library changes
+
+#### `package:kernel`
+
+*   **Breaking change:** The `klass` getter on the `InstanceConstant` class in
+    the Kernel AST API has been renamed to `classNode` for consistency.
+
+*   **Breaking change:** Updated `Link` implementation to utilize true symbolic
+    links instead of junctions on Windows. Existing junctions will continue to
+    work with the new `Link` implementation, but all new links will create
+    symbolic links.
+    
+    To create a symbolic link, Dart must be run with
+    administrative privileges or Developer Mode must be enabled, otherwise a
+    `FileSystemException` will be raised with errno set to
+    `ERROR_PRIVILEGE_NOT_HELD` (Issue [33966]).
+
+[33966]: https://github.com/dart-lang/sdk/issues/33966
+
+### Dart VM
+
+### Tool Changes
+
+#### Analyzer
+
+*   The `DEPRECATED_MEMBER_USE` hint was split into two hints:
+
+    *   `DEPRECATED_MEMBER_USE` reports on usage of `@deprecated` members
+        declared in a different package.
+    *   `DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE` reports on usage of
+        `@deprecated` members declared in the same package.
+
+### Linter
+
+The linter was bumped to `0.1.79` which introduces the following linter improvements to the SDK:
+
+* `unnecessary_parenthesis` updated to play nicer with cascades
+* new lint: `use_full_hex_values_for_flutter_colors`
+* new lint: `prefer_null_aware_operators`
+* miscellaneous documentation fixes
+* removed deprecated lints from the "all options" sample
+* stopped registering "default lints"
+* `hash_and_equals` fixed to respect `hashCode` fields
+
+
+#### Other Tools
+
 ## 2.1.1-dev.3.2
 
 * Cherry-pick 9d25cc93e850d4717cdc9e1c4bd3623e09c16d47 to dev
@@ -47,7 +155,9 @@
 
 ### Dart VM
 
-In previous releases it was possible to violate static types using dart:mirrors but this bug is fixed now. Meaning that the code below would run without any TypeErrors and print "impossible" output.
+In previous releases it was possible to violate static types using
+`dart:mirrors` but this bug is fixed now. Meaning that the code below would run
+without any TypeErrors and print "impossible" output.
 
 ```dart
 import 'dart:mirrors';
@@ -105,7 +215,7 @@
       Common front-end. On large apps, the fix can cut down 2/3 of the time
       spent on this task.
 
-    * We fixed a bug in how inferred types were miscategorized (#35311). The old
+    * We fixed a bug in how inferred types were miscategorized (Issue [35311]). The old
       behavior was unsound and could produce broken programs. The fix may cause
       more code to be pulled into the main output unit.
 
@@ -137,14 +247,15 @@
       }
       ```
 
-    * Because the new implementation might require you to inspect and fix
-      your app, we exposed two temporary flags:
+  Because the new implementation might require you to inspect and fix
+  your app, we exposed two temporary flags:
 
-        * `--report-invalid-deferred-types`: when provided, we will run
-          both the old and new algorithm and report where the issue was
-          detected.
+    * `--report-invalid-deferred-types`: when provided, we will run both the
+      old and new algorithm and report where the issue was detected.
 
-        * `--new-deferred-split`: enables the new algorithm.
+    * `--new-deferred-split`: enables the new algorithm.
+
+[35311]: https://github.com/dart-lang/sdk/issues/35311
 
 #### dartdoc
 
@@ -2783,7 +2894,7 @@
     people in practice.
 
   * **Breaking:** Support for `barback` versions prior to 0.15.0 (released July
-    2014) has been dropped. Pub will no longer install these older barback
+    1)    has been dropped. Pub will no longer install these older barback
     versions.
 
   * `pub serve` now GZIPs the assets it serves to make load times more similar
diff --git a/DEPS b/DEPS
index ae2451a..6fe9b46 100644
--- a/DEPS
+++ b/DEPS
@@ -36,7 +36,7 @@
   "chromium_git": "https://chromium.googlesource.com",
   "fuchsia_git": "https://fuchsia.googlesource.com",
 
-  "co19_2_rev": "9c03cd19b61a9307db192f174a7e7a1ec6759bb2",
+  "co19_2_rev": "31f7dc1e222910ce64ab57ffee286382b03446a4",
 
   # As Flutter does, we use Fuchsia's GN and Clang toolchain. These revision
   # should be kept up to date with the revisions pulled by the Flutter engine.
@@ -81,13 +81,11 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164
   "dart_style_tag": "1.2.2",  # Please see the note above before updating.
 
-  "dartdoc_tag" : "v0.27.0",
-  "file_rev": "515ed1dd48740ab14b625de1be464cb2bca4fefd",  # 5.0.6
+  "dartdoc_tag" : "v0.28.0",
   "fixnum_tag": "0.10.9",
-  "func_rev": "25eec48146a58967d75330075ab376b3838b18a8",
   "glob_tag": "1.1.7",
   "html_tag" : "0.13.3+2",
-  "http_io_rev": "265e90afbffacb7b2988385d4a6aa2f14e970d44",
+  "http_io_rev": "57da05a66f5bf7df3dd7aebe7b7efe0dfc477baa",
   "http_multi_server_tag" : "2.0.5",
   "http_parser_tag" : "3.1.1",
   "http_retry_tag": "0.1.1",
@@ -97,23 +95,22 @@
   "intl_tag": "0.15.7",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "2.0.9",
-  "linter_tag": "0.1.78",
+  "linter_tag": "0.1.79",
   "logging_tag": "0.11.3+2",
+  "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "markdown_tag": "2.0.2",
   "matcher_tag": "0.12.3",
   "mime_tag": "0.9.6+2",
   "mockito_tag": "d39ac507483b9891165e422ec98d9fb480037c8b",
-  "mustache4dart_tag" : "v2.1.2",
+  "mustache_tag" : "5e81b12215566dbe2473b2afd01a8a8aedd56ad9",
   "oauth2_tag": "1.2.1",
   "observatory_pub_packages_rev": "0894122173b0f98eb08863a7712e78407d4477bc",
   "package_config_tag": "1.0.5",
   "package_resolver_tag": "1.0.4",
   "path_tag": "1.6.2",
-  "platform_rev": "c368ca95775a4ec8d0b60899ce51299a9fbda399", # 2.2.0
   "plugin_tag": "f5b4b0e32d1406d62daccea030ba6457d14b1c47",
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_tag": "1.3.6",
-  "process_rev": "b8d73f0bad7be5ab5130baf10cd042aae4366d7c", # 3.0.5
   "protobuf_tag": "0.9.0",
   "pub_rev": "9f00679ef47bc79cadc18e143720ade6c06c0100",
   "pub_semver_tag": "1.4.2",
@@ -180,6 +177,10 @@
       "dep_type": "cipd",
   },
 
+  Var("dart_root") + "/third_party/markupsafe":
+      Var("chromium_git") + "/chromium/src/third_party/markupsafe.git" +
+      "@" + Var("markupsafe_rev"),
+
   Var("dart_root") + "/third_party/zlib":
       Var("chromium_git") + "/chromium/src/third_party/zlib.git" +
       "@" + Var("zlib_rev"),
@@ -248,12 +249,8 @@
       Var("dart_git") + "dart2js_info.git" + "@" + Var("dart2js_info_tag"),
   Var("dart_root") + "/third_party/pkg/dartdoc":
       Var("dart_git") + "dartdoc.git" + "@" + Var("dartdoc_tag"),
-  Var("dart_root") + "/third_party/pkg/file":
-      Var("dart_git") + "file.dart.git" + "@" + Var("file_rev"),
   Var("dart_root") + "/third_party/pkg/fixnum":
       Var("dart_git") + "fixnum.git" + "@" + Var("fixnum_tag"),
-  Var("dart_root") + "/third_party/pkg/func":
-      Var("dart_git") + "func.git" + "@" + Var("func_rev"),
   Var("dart_root") + "/third_party/pkg/glob":
       Var("dart_git") + "glob.git" + "@" + Var("glob_tag"),
   Var("dart_root") + "/third_party/pkg/html":
@@ -289,10 +286,10 @@
       Var("dart_git") + "mime.git" + "@" + Var("mime_tag"),
   Var("dart_root") + "/third_party/pkg/mockito":
       Var("dart_git") + "mockito.git" + "@" + Var("mockito_tag"),
-  Var("dart_root") + "/third_party/pkg/mustache4dart":
-      Var("chromium_git")
-      + "/external/github.com/valotas/mustache4dart.git"
-      + "@" + Var("mustache4dart_tag"),
+  Var("dart_root") + "/third_party/pkg/mustache":
+      Var("dart_git")
+      + "external/github.com/xxgreg/mustache"
+      + "@" + Var("mustache_tag"),
   Var("dart_root") + "/third_party/pkg/oauth2":
       Var("dart_git") + "oauth2.git" + "@" + Var("oauth2_tag"),
   Var("dart_root") + "/third_party/observatory_pub_packages":
@@ -306,14 +303,10 @@
       + "@" + Var("package_resolver_tag"),
   Var("dart_root") + "/third_party/pkg/path":
       Var("dart_git") + "path.git" + "@" + Var("path_tag"),
-  Var("dart_root") + "/third_party/pkg/platform":
-      Var("dart_git") + "platform.dart.git" + "@" + Var("platform_rev"),
   Var("dart_root") + "/third_party/pkg/plugin":
       Var("dart_git") + "plugin.git" + "@" + Var("plugin_tag"),
   Var("dart_root") + "/third_party/pkg/pool":
       Var("dart_git") + "pool.git" + "@" + Var("pool_tag"),
-  Var("dart_root") + "/third_party/pkg/process":
-      Var("dart_git") + "process.dart.git" + "@" + Var("process_rev"),
   Var("dart_root") + "/third_party/pkg/protobuf":
       Var("dart_git") + "protobuf.git" + "@" + Var("protobuf_tag"),
   Var("dart_root") + "/third_party/pkg/pub_semver":
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index f7291e8..8bf1471 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -22,6 +22,8 @@
   upstream = input_api.change._upstream
   unformatted_files = []
   for git_file in input_api.AffectedTextFiles():
+    if git_file.LocalPath().startswith("pkg/front_end/testcases/"):
+      continue
     filename = git_file.AbsoluteLocalPath()
     if filename.endswith(extension) and hasFormatErrors(filename=filename):
       old_version_has_errors = False
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 6edb3b3..0a6a259 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -91,6 +91,11 @@
       ldflags += [ "-Wl,--fatal-warnings" ]
     }
 
+    # Enable mitigations for Cortex-A53 Erratum #843419 bug.
+    if (current_cpu == "arm64" && is_clang) {
+      ldflags += [ "-Wl,--fix-cortex-a53-843419" ]
+    }
+
     # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer and
     # MemorySanitizer
     if (using_sanitizer) {
diff --git a/docs/language/dart.sty b/docs/language/dart.sty
index 0776ec0..0ad847e 100644
--- a/docs/language/dart.sty
+++ b/docs/language/dart.sty
@@ -96,7 +96,7 @@
 
 % Auxiliary functions.
 \newcommand{\flatten}[1]{\ensuremath{\mbox{\it flatten}({#1})}}
-\newcommand{\basetype}[1]{\ensuremath{\mbox{\it basetype}({#1})}}
+\newcommand{\futureOrBase}[1]{\ensuremath{\mbox{\it futureOrBase}({#1})}}
 \newcommand{\overrides}[1]{\ensuremath{\mbox{\it overrides}({#1})}}
 \newcommand{\inherited}[1]{\ensuremath{\mbox{\it inherited}({#1})}}
 
@@ -133,6 +133,11 @@
 \newcommand{\IndexCustom}[2]{%
   \leavevmode\marginpar{\ensuremath{\diamond}}\emph{#1}\index{#2}}
 
+% Used when one concept should have >1 entry in the index. Does not add
+% the diamond in the margin and shows no text where the command occurs.
+% Intended to be used immediately after another \Index... command.
+\newcommand{\IndexExtraEntry}[1]{\index{#1}}
+
 % Used for a defining occurrence of a phrase, adding it to the index.
 \newcommand{\Index}[1]{\IndexCustom{#1}{#1}}
 
@@ -184,10 +189,15 @@
   {#1}_1\FunctionTypeExtends{#2}_1,\,\ldots,\ %
   {#1}_{#3}\FunctionTypeExtends{#2}_{#3}}}
 
-% Used to specify non-generic function types: Same syntax as in source.
+% Used to specify simple non-generic function types: Same syntax as in source.
 % Arguments: Return type, formal parameter declarations.
 \newcommand{\FunctionTypeSimple}[2]{\code{\ensuremath{#1}\ \FUNCTION({#2})}}
 
+% Used to specify simple generic function types: Same syntax as in source.
+% Arguments: Return type, formal parameter declarations.
+\newcommand{\FunctionTypeSimpleGeneric}[3]{\code{%
+  \ensuremath{#1}\ \FUNCTION<{#2}>({#3})}}
+
 % Used to specify function types: Same syntax as in source.
 % Arguments: Return type, spacer, type parameter name, bound name,
 %   number of type parameters, formal parameter declarations.
@@ -237,13 +247,13 @@
 %   name of optional parameters, number of optional parameters.
 \newcommand{\FunctionTypeNamed}[9]{%
   \FunctionType{#1}{#2}{#3}{#4}{#5}{%
-    \FunctionTypePositionalArguments{#6}{#7}{#8}{#9}}}
+    \FunctionTypeNamedArguments{#6}{#7}{#8}{#9}}}
 
 % Same as \FunctionType except suitable for inline usage, hence omitting
 % the spacer argument.
 \newcommand{\RawFunctionTypeNamed}[8]{%
   \RawFunctionType{#1}{#2}{#3}{#4}{%
-    \FunctionTypePositionalArguments{#5}{#6}{#7}{#8}}}
+    \FunctionTypeNamedArguments{#5}{#6}{#7}{#8}}}
 
 % Used to specify function types with no optional parameters:
 % Arguments: Return type, spacer, type parameter name, bound name,
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 2202ec5..04bdb83 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -732,10 +732,10 @@
 A static warning must be reported by a Dart compiler before the associated code is executed.
 
 \LMHash{}%
-When this specification says that a \Index{run-time error} occurs,
+When this specification says that a \Index{dynamic error} occurs,
 it means that a corresponding error object is thrown.
 When it says that a \Index{dynamic type error} occurs,
-it represents a failed run-time type check,
+it represents a failed type check at run time,
 and the object which is thrown implements \code{TypeError}.
 
 \LMHash{}%
@@ -944,6 +944,7 @@
 that has been initialized by means of an initializing formal of a constructor $k$
 is also initialized in the initializer list of $k$ (\ref{initializerLists}).
 
+%% TODO(eernst): Not quite true, because of special lookup for assignment!
 A static final variable $v$ does not induce a setter,
 so unless a setter named \code{$v$=} is in scope
 it is a compile-time error to assign to $v$.
@@ -956,6 +957,7 @@
 but initialization and assignment is not the same thing.
 When the receiver has type \DYNAMIC{}
 such an assignment is not a compile-time error,
+% This error can occur because the receiver is dynamic.
 but if there is no setter it will cause a dynamic error.
 }
 
@@ -1002,8 +1004,9 @@
 }
 
 \LMHash{}%
-It is a dynamic type error if $o$ is not the null object (\ref{null})
-and the dynamic type of $o$ is not
+% This error can occur due to implicit casts, and
+% for instance variables also when a setter is called dynamically.
+It is a dynamic type error if the dynamic type of $o$ is not
 a subtype of the actual type of the variable $v$
 (\ref{actualTypeOfADeclaration}).
 
@@ -1584,8 +1587,10 @@
 
 \LMHash{}%
 In this specification,
-the notation used to denote the type of a function follows
-the syntax of the language, except that \EXTENDS{} is abbreviated to
+the notation used to denote the type of a function,
+that is, a \Index{function type},
+follows the syntax of the language,
+except that \EXTENDS{} is abbreviated to
 \FunctionTypeExtends.
 This means that every function type is of one of the forms
 \FunctionTypePositionalStd{T_0}
@@ -1594,7 +1599,8 @@
 \noindent
 where $T_0$ is the return type,
 $X_j$ are the formal type parameters with bounds $B_j$, $j \in 1 .. s$,
-$T_j$ are the formal parameter types for $j \in 1 .. n + k$.
+$T_j$ are the formal parameter types for $j \in 1 .. n + k$,
+and $x_{n+j}$ are the names of named parameters for $j \in 1 .. k$.
 Non-generic function types are covered by the case $s = 0$,
 where the type parameter declaration list
 \code{<\ldots{}>}
@@ -1664,7 +1670,8 @@
 type parameters \TypeParametersStd,
 required formal parameter types \List{T}{1}{n},
 return type $T_0$,
-and named parameters \PairList{T}{x}{n+1}{n+k}.
+and named parameters \PairList{T}{x}{n+1}{n+k},
+where $x_{n+j}$, $j \in 1 .. k$ may or may not have a default value.
 Then the static type of $F$ is
 \FunctionTypeNamedStd{T_0}.
 
@@ -1684,12 +1691,12 @@
 $u$ is a class that implements the built-in class \FUNCTION{};
 $u$ is a subtype of $t$;
 and $u$ is not a subtype of any function type which is a proper subtype of $t$.
-\commentary{
+\commentary{%
 If we had omitted the last requirement then
 \code{f \IS{} int\,\FUNCTION([int])}
 could evaluate to \TRUE{} with the declaration
 \code{\VOID{} f()\,\{\}},
-e.g., by letting $u$ be \code{Null}.
+which is obviously not the intention.%
 }
 
 \rationale{
@@ -1746,12 +1753,10 @@
 
 \begin{grammar}
 <classDefinition> ::= <metadata> \ABSTRACT{}? \CLASS{} <identifier> <typeParameters>?
-  \gnewline{} <superclass>? <mixins>? <interfaces>?
+  \gnewline{} <superclass>? <interfaces>?
   \gnewline{} `{' (<metadata> <classMemberDefinition>)* `}'
   \alt <metadata> \ABSTRACT{}? \CLASS{} <mixinApplicationClass>
 
-<mixins> ::= \WITH{} <typeNotVoidList>
-
 <typeNotVoidList> ::= <typeNotVoid> (`,' <typeNotVoid>)*
 
 <classMemberDefinition> ::= <declaration> `;'
@@ -1768,10 +1773,10 @@
   \alt <constructorSignature> (<redirection> | <initializers>)?
   \alt \EXTERNAL{} <constantConstructorSignature>
   \alt \EXTERNAL{} <constructorSignature>
-  \alt ((\EXTERNAL{} \STATIC{}?))? <getterSignature>
-  \alt ((\EXTERNAL{} \STATIC{}?))? <setterSignature>
+  \alt (\EXTERNAL{} \STATIC{}?)? <getterSignature>
+  \alt (\EXTERNAL{} \STATIC{}?)? <setterSignature>
   \alt \EXTERNAL{}? <operatorSignature>
-  \alt ((\EXTERNAL{} \STATIC{}?))? <functionSignature>
+  \alt (\EXTERNAL{} \STATIC{}?)? <functionSignature>
   \alt \STATIC{} (\FINAL{} | \CONST{}) <type>? <staticFinalDeclarationList>
   \alt \FINAL{} <type>? <initializedIdentifierList>
   \alt (\STATIC{} | \COVARIANT{})? (\VAR{} | <type>) <initializedIdentifierList>
@@ -1883,15 +1888,12 @@
 (in which case it will be overridden by another \code{noSuchMethod} forwarder).
 }
 
-% making an exception for the setters generated for final fields is tempting but problematic.
-% If a super type defines a setter, it will be overridden yet have no impact on the interface.
-% Maybe the final field hides the setter in scope?
-% I think the original rules were best.
-
 \commentary{
 It is a compile-time error if a class declares two members of the same name,
-either because it declares the same name twice in the same scope (\ref{scoping}),
-or because it declares a static member and an instance member with the same name
+either because it declares the same name twice in the same scope
+(\ref{scoping}),
+or because it declares a static member and an instance member
+with the same name
 (\ref{classMemberConflicts}).
 }
 
@@ -2030,71 +2032,72 @@
 
 \LMHash{}%
 The following names are allowed for user-defined operators:
-\syntax{`<'},
-\syntax{`>'},
-\syntax{`<='},
-\syntax{`>='},
-\syntax{`=='},
-\syntax{`-'},
-\syntax{`+'},
-\syntax{`/'},
-\syntax{`~'},
-\syntax{`*'},
-\syntax{`\%'},
-\syntax{`|'},
-\syntax{`^'},
-\syntax{`\&'},
-\syntax{`\ltlt'},
-\syntax{`\gtgt'},
-\syntax{`\gtgtgt'},
-\syntax{`[]='},
-\syntax{`[]'},
-\syntax{`~'}.
+\lit{<},
+\lit{>},
+\lit{<=},
+\lit{>=},
+\lit{==},
+\lit{-},
+\lit{+},
+\lit{/},
+\lit{\~{}/},
+\lit{*},
+\lit{\%},
+\lit{|},
+\lit{\^},
+\lit{\&},
+\lit{\ltlt},
+\lit{\gtgt},
+\lit{\gtgtgt},
+\lit{[]=},
+\lit{[]},
+\lit{\~{}}.
 
 \LMHash{}%
 It is a compile-time error if the arity of the user-declared operator
-\syntax{`[]='} is not 2.
+\lit{[]=} is not 2.
 It is a compile-time error if the arity of a user-declared operator with one of the names:
-\syntax{`<'},
-\syntax{`>'},
-\syntax{`<='},
-\syntax{`>='},
-\syntax{`=='},
-\syntax{`-'},
-\syntax{`+'},
-\syntax{`~/'},
-\syntax{`/'},
-\syntax{`*'},
-\syntax{`\%'},
-\syntax{`|'},
-\syntax{`^'},
-\syntax{`\&'},
-\syntax{`\ltlt'},
-\syntax{`\gtgt'},
-\syntax{`\gtgtgt'},
-\syntax{`[]'}
+\lit{<},
+\lit{>},
+\lit{<=},
+\lit{>=},
+\lit{==},
+\lit{-},
+\lit{+},
+\lit{\~{}/},
+\lit{/},
+\lit{*},
+\lit{\%},
+\lit{|},
+\lit{\^},
+\lit{\&},
+\lit{\ltlt},
+\lit{\gtgt},
+\lit{\gtgtgt},
+\lit{[]}
 is not 1.
 It is a compile-time error if the arity of the user-declared operator
-\syntax{`-'}
+\lit{-}
 is not 0 or 1.
 
 \commentary{
-The \syntax{`-'} operator is unique
+The \lit{-} operator is unique
 in that two overloaded versions are permitted.
 If the operator has no arguments, it denotes unary minus.
 If it has an argument, it denotes binary subtraction.
 }
 
 \LMHash{}%
-The name of the unary operator \syntax{`-'} is \code{unary-}.
+The name of the unary operator \lit{-} is \code{unary-}.
 
 \rationale{
-This device allows the two methods to be distinguished for purposes of method lookup, override and reflection.
+This device allows the two methods to be distinguished
+for purposes of method lookup, override and reflection.
 }
 
 \LMHash{}%
 It is a compile-time error if the arity of the user-declared operator
-\syntax{`~'}
+\lit{\~{}}
 is not 0.
 
 \LMHash{}%
@@ -2102,25 +2105,26 @@
 
 \LMHash{}%
 It is a static warning if the return type of a user-declared operator
-\syntax{`[]='}
+\lit{[]=}
 is explicitly declared and not \VOID{}.
 
 \commentary{
 If no return type is specified for a user-declared operator
-\syntax{`[]='},
+\lit{[]=},
 its return type is \VOID{} (\ref{typeOfAFunction}).
 }
 
 \rationale{
 The return type is \VOID{} because
 a return statement in an implementation of operator
-\syntax{`[]='}
+\lit{[]=}
 does not return a value.
-Consider a non-throwing evaluation of an expression $e$ of the form \code{$e_1$[$e_2$] = $e_3$},
+Consider a non-throwing evaluation of an expression $e$ of the form
+\code{$e_1$[$e_2$] = $e_3$},
 and assume that the evaluation of $e_3$ yields an instance $o$.
 $e$ will then evaluate to $o$,
 and even if the executed body of operator
-\syntax{`[]='}
+\lit{[]=}
 completes with a value $o'$,
 that is, if $o'$ is returned, that value is simply ignored.
 The rationale for this behavior is that assignments should be guaranteed to evaluate to the assigned value.
@@ -2420,6 +2424,61 @@
 \end{dartCode}
 
 
+\subsubsection{The Operator `=='}
+\LMLabel{theOperatorEqualsEquals}
+
+\LMHash{}%
+The operator \lit{==} is used implicitly in certain situations,
+and in particular constant expressions
+(\ref{constants})
+give rise to constraints on that operator.
+In order to specify these constraints just once we introduce the notion of a
+% Neither \syntax nor \lit works, so we fall back to `\code{==}'.
+\IndexCustom{primitive operator `\code{==}'}{%
+  operator `\code{==}'!primitive}:
+
+\begin{itemize}
+\item Every instance of type \code{int} and \code{String}
+  has a primitive operator \lit{==}.
+\item Every instance of type \code{Symbol}
+  which was originally obtained by evaluation of a literal symbol or
+  a constant invocation of a constructor of the \code{Symbol} class
+  has a primitive operator \lit{==}.
+\item Every instance of type \code{Type}
+  which was originally obtained by evaluating a constant type literal
+  (\ref{dynamicTypeSystem})
+  has a primitive operator \lit{==}.
+\item An instance $o$ has a primitive operator \lit{==}
+  if the dynamic type of $o$ is a class $C$,
+  and $C$ has a primitive operator \lit{==}.
+\item The class \code{Object} has a primitive operator \lit{==}.
+\item A class $C$ has a primitive operator \lit{==}
+  if it does not have an implementation of the operator \lit{==}
+  that overrides the one inherited from \code{Object}.
+  \commentary{%
+  In particular, the following have a primitive operator \lit{==}:
+  The null object (\ref{null}),
+  function objects obtained by function closurization of
+  a static method or a top-level function
+  (\ref{functionClosurization}),
+  instances of type \code{bool}
+  (\ref{booleans}),
+  and instances obtained by evaluation of a list literal
+  (\ref{lists}),
+  a map literal
+  (\ref{maps}), or
+  a set literal
+  (\ref{sets}).
+  }
+\end{itemize}
+
+\LMHash{}%
+When we say that the operator \lit{==} of a given instance or class
+\IndexCustom{is not primitive}{operator `\code{==}'!is not primitive},
+it means that it is not true that said instance or class
+has a primitive operator \lit{==}.
+
+
 \subsection{Getters}
 \LMLabel{getters}
 
@@ -2639,8 +2698,10 @@
 It is a compile-time error if the name of a constructor is not a constructor name.
 
 \LMHash{}%
-The \Index{function type of a constructor} $k$ is the function type whose
-return type is the class that contains the declaration of $k$,
+The
+\IndexCustom{function type of a constructor}{function type!of a constructor}
+$k$ is the function type
+whose return type is the class that contains the declaration of $k$,
 and whose formal parameter types, optionality, and names of named parameters
 correspond to the declaration of $k$.
 
@@ -2711,10 +2772,15 @@
 }
 
 \LMHash{}%
-Initializing formals are executed during the execution of generative constructors detailed below.
-Executing an initializing formal \code{\THIS{}.\id} causes the instance variable \id{} of the immediately surrounding class to be assigned the value of the corresponding actual parameter,
-%% TODO(eernst): This should be a compile-time error -- check, revise if true!
-unless \id{} is a final variable that has already been initialized, in which case a run-time error occurs.
+Initializing formals are executed during
+the execution of generative constructors detailed below.
+Executing an initializing formal \code{\THIS{}.\id}
+causes the instance variable \id{} of the immediately surrounding class
+to be assigned the value of the corresponding actual parameter,
+% This can occur due to a failing implicit cast.
+unless the assigned value has a dynamic type
+which is not a subtype of the declared type of the instance variable \id{},
+in which case a dynamic error occurs.
 
 \commentary{
 The above rule allows initializing formals to be used as optional parameters:
@@ -2822,10 +2888,14 @@
 must be a potentially constant expression (\ref{constantConstructors}).
 
 \LMHash{}%
-It is a dynamic type error if an actual argument passed in an invocation of a redirecting generative constructor $k$
+% This error can occur due to a failed implicit cast.
+It is a dynamic type error if an actual argument passed
+in an invocation of a redirecting generative constructor $k$
 is not a subtype of the actual type (\ref{actualTypeOfADeclaration})
 of the corresponding formal parameter in the declaration of $k$.
-It is a dynamic type error if an actual argument passed to the redirectee $k'$ of a redirecting generative constructor
+% This error can occur due to a failed implicit cast.
+It is a dynamic type error if an actual argument passed
+to the redirectee $k'$ of a redirecting generative constructor
 is not a subtype of the actual type
 (\ref{actualTypeOfADeclaration})
 of the corresponding formal parameter in the declaration of the redirectee.
@@ -2964,9 +3034,10 @@
 Execution then proceeds as follows:
 
 \LMHash{}%
-The instance variable declarations of the immediately enclosing class are visited in the order they appear in the program text.
+The instance variable declarations of the immediately enclosing class
+are visited in the order they appear in the program text.
 For each such declaration $d$, if $d$ has the form
-\code{\syntax{finalConstVarOrType} $v$ = $e$; }
+\code{\synt{finalConstVarOrType} $v$ = $e$; }
 then $e$ is evaluated to an object $o$
 and the instance variable $v$ of $i$ is bound to $o$.
 
@@ -3015,9 +3086,9 @@
 \LMHash{}%
 First, the expression $e$ is evaluated to an object $o$.
 Then, the instance variable $v$ of $i$ is bound to $o$.
-It is a dynamic type error if $o$ is not the null object
-(\ref{null})
-and the dynamic type of $o$ is not a subtype of the actual type
+% This error can occur due to an implicit cast.
+It is a dynamic type error if the dynamic type of $o$ is not
+a subtype of the actual type
 (\ref{actualTypeOfADeclaration})
 of the instance variable $v$.
 
@@ -3080,6 +3151,7 @@
 It is a compile-time error if $M$ is not the name of the immediately enclosing class.
 
 \LMHash{}%
+% This error can occur due to an implicit cast.
 It is a dynamic type error if a factory returns a non-null object
 whose type is not a subtype of its actual
 (\ref{actualTypeOfADeclaration})
@@ -3166,12 +3238,15 @@
 
 \rationale{
 We require a subtype match
-(rather than the more forgiving assignable match which is used with a generative redirecting constructor),
-because a factory redirecting constructor $k$ always invokes its redirectee $k'$
-with exactly the same actual arguments that $k$ received.
+(rather than the more forgiving assignable match
+which is used with a generative redirecting constructor),
+because a factory redirecting constructor $k$ always invokes
+its redirectee $k'$ with
+exactly the same actual arguments that $k$ received.
 This means that a downcast on an actual argument
 ``between'' $k$ and $k'$
-would either be unused because the actual argument has the type required by $k'$,
+would either be unused because the actual argument has
+the type required by $k'$,
 or it would amount to a dynamic error which is simply delayed a single step.
 }
 
@@ -3184,10 +3259,10 @@
 \LMHash{}%
 It is a compile-time error if $k$ explicitly specifies a default value for an optional parameter.
 
-\commentary{
+\rationale{%
 Default values specified in $k$ would be ignored,
 since it is the \emph{actual} parameters that are passed to $k'$.
-Hence, default values are disallowed.
+Hence, default values are disallowed.%
 }
 
 \LMHash{}%
@@ -3233,6 +3308,7 @@
 and $k'$ is the redirectee of $k$.
 
 \LMHash{}%
+% This error can occur due to an implicit cast.
 It is a dynamic type error if an actual argument passed in an invocation of $k$
 is not a subtype of the actual type (\ref{actualTypeOfADeclaration})
 of the corresponding formal parameter in the declaration of $k$.
@@ -3330,7 +3406,7 @@
 \CLASS{} D \{
   \FINAL{} w;
   \CONST{} D.makeList(p): w = \CONST{} [p]; // \comment{compile-time error}
-  \CONST{} D.makeMap(p): w = \CONST{} \{``help'': q\}; // \comment{compile-time error}
+  \CONST{} D.makeMap(p): w = \CONST{} \{"help": q\}; // \comment{compile-time error}
   \CONST{} D.makeC(p): w = \CONST{} C(p, 12); // \comment{compile-time error}
 \}
 \end{dartCode}
@@ -3431,7 +3507,10 @@
 for class \code{Object}.
 
 \begin{grammar}
-<superclass> ::= \EXTENDS{} <typeNotVoid>
+<superclass> ::= \EXTENDS{} <typeNotVoid> <mixins>?
+    \alt <mixins>
+
+<mixins> ::= \WITH{} <typeNotVoidList>
 \end{grammar}
 
 %The superclass clause of a class C is processed within the enclosing scope of the static scope of C.
@@ -3445,7 +3524,7 @@
 \LMHash{}%
 It is a compile-time error if the type in the \EXTENDS{} clause of a class $C$ is
 a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}),
-an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
+an enumerated type (\ref{enums}),
 a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
 or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
 
@@ -3635,7 +3714,7 @@
 \LMHash{}%
 It is a compile-time error if an element in the type list of the \IMPLEMENTS{} clause of a class $C$ is
 a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}),
-an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
+an enumerated type (\ref{enums}),
 a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
 or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
 It is a compile-time error if two elements in the type list of the \IMPLEMENTS{} clause of a class $C$ specifies the same type $T$.
@@ -4016,7 +4095,7 @@
 \Case{Methods and setters}
 In this case $M_0$ consists of setter signatures only,
 or method signatures only,
-because the name \id{} in the former case always end in \syntax{`='},
+because the name \id{} in the former case always ends in \lit{=},
 which is never true in the latter case.
 
 \LMHash{}%
@@ -4155,6 +4234,7 @@
 It is a compile-time error
 if the computation of said combined member signature fails.
 
+
 \subsubsection{Correct Member Overrides}
 \LMLabel{correctMemberOverrides}
 
@@ -4218,33 +4298,16 @@
 
 \LMHash{}%
 A mixin describes the difference between a class and its superclass.
-A mixin is always derived from an existing class declaration.
+A mixin is either derived from an existing class declaration
+or introduced by a mixin declaration.
 
 \LMHash{}%
-It is a compile-time error to derive a mixin from a class which explicitly declares a generative constructor.
-It is a compile-time error to derive a mixin from a class which has a superclass other than \code{Object}.
+Mixin application occurs when one or more mixins are mixed into a class declaration via its \WITH{} clause (\ref{mixinApplication}).
+Mixin application may be used to extend a class per section \ref{classes};
+alternatively, a class may be defined as a mixin application as described in the following section.
 
-\rationale{
-This restriction is temporary.
-We expect to remove it in later versions of Dart.
-
-The restriction on constructors simplifies the construction of mixin applications because the process of creating instances is simpler.
-}
-
-
-\subsection{Mixin Application}
-\LMLabel{mixinApplication}
-
-\LMHash{}%
-A mixin may be applied to a superclass, yielding a new class.
-Mixin application occurs when one or more mixins are mixed into a class declaration via its \WITH{} clause.
-The mixin application may be used to extend a class per section \ref{classes};
-alternatively, a class may be defined as a mixin application as described in this section.
-It is a compile-time error if an element in the type list of the \WITH{} clause of a mixin application is
-a type variable (\ref{generics}), a type alias that does not denote a class (\ref{typedef}),
-an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
-a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
-or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
+\subsection{Mixin Classes}
+\LMLabel{mixinClasses}
 
 \begin{grammar}
 <mixinApplicationClass> ::= \gnewline{}
@@ -4254,26 +4317,207 @@
 \end{grammar}
 
 \LMHash{}%
-A mixin application of the form \code{$S$ \WITH{} $M$;} for the name $N$ defines a class $C$ with superclass $S$ and name $N$.
+It is a compile-time error if an element in the type list of the \WITH{} clause of a mixin application is
+a type variable (\ref{generics}),
+a function type (\ref{functionTypes}),
+a type alias that does not denote a class (\ref{typedef}),
+an enumerated type (\ref{enums}),
+a deferred type (\ref{staticTypes}),
+type \DYNAMIC{} (\ref{typeDynamic}),
+type \VOID{} (\ref{typeVoid}),
+or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
+If $T$ is a type in a \WITH{} clause, \IndexCustom{the mixin of}{type!mixin of}
+$T$ is either the mixin derived from $T$ if $T$ denotes a class,
+or the mixin introduced by $T$ if $T$ denotes a mixin declaration.
 
 \LMHash{}%
-A mixin application of the form \code{$S$ \WITH{} $M_1,\ \ldots,\ M_k$;} for the name $N$ defines a class $C$ whose superclass is the application of the mixin composition (\ref{mixinComposition}) $M_{k-1} * \ldots * M_1$ to $S$ of a name that is a fresh identifer, and whose name is $N$.
-\rationale{The name of the resulting class is necessary because it is part of the names of the introduced constructors.}
+Let $D$ be a mixin application class declaration of the form
+\begin{normativeDartCode}
+\ABSTRACT? \CLASS{} $N$ = $S$ \WITH{} $M_1$, \ldots{}, $M_n$ \IMPLEMENTS{} $I_1$, \ldots, $I_k$;
+\end{normativeDartCode}
 
 \LMHash{}%
-In both cases above, $C$ declares the same instance members as $M$ (respectively, $M_k$),
-and it does not declare any static members.
-If any of the instance variables of $M$ (respectively, $M_k$) have initializers,
-they are executed in the instance scope of $M$ (respectively, $M_k$)
-to initialize the corresponding instance variables of $C$.
+It is a compile-time error if $S$ is an enumerated type (\ref{enums}).
+It is a compile-time error if any of $M_1, \ldots, M_k$ is an enumerated type (\ref{enums}).
+It is a compile-time error if a well formed mixin cannot be derived from each of $M_1, \ldots, M_k$.
+
+\LMHash{}%
+The effect of $D$ in library $L$ is to introduce the name $N$ into the scope of $L$, bound to the class (\ref{classes}) defined by the clause \code{$S$ \WITH{} $M_1$, \ldots{}, $M_n$} with name $N$, as described below.
+If $k > 0$ then the class also implements $I_1$, \ldots{}, $I_k$.
+If{}f the class declaration is prefixed by the built-in identifier \ABSTRACT{}, the class being defined is made an abstract class.
+
+\LMHash{}%
+A clause of the form \code{$S$ \WITH{} $M_1$, \ldots{}, $M_n$}
+with name $N$ defines a class as follows:
+
+\LMHash{}%
+If there is only one mixin ($n = 1$), then \code{$S$ \WITH{} $M_1$}
+defines the class yielded by the mixin application (\ref{mixinApplication})
+of the mixin of $M_1$ (\ref{mixinDeclaration}) to the class denoted by
+$S$ with name $N$.
+
+\LMHash{}%
+If there is more than one mixin ($n > 1$), then
+let $X$ be the class defined by \code{$S$ \WITH{} $M_1$, \ldots{}, $M_{n-1}$}
+with name $F$, where $F$ is a fresh name, and make $X$ abstract.
+Then \code{$S$ \WITH{} $M_1$, \ldots{}, $M_n$} defines the class yielded
+by the mixin application of the mixin of $M_n$ to the class $X$ with name $N$.
+
+\LMHash{}%
+In either case, let $K$ be a class declaration with the same constructors, superclass, interfaces and instance members as the defined class.
+It is a compile-time error if the declaration of $K$ would cause a compile-time error.
+% TODO(eernst): Not completely!
+% We do not want super-invocations on covariant implementations
+% to be compile-time errors.
+
+\commentary{
+It is an error, for example, if $M$ contains a member declaration $d$ which overrides a member signature $m$ in the interface of $S$, but which is not a correct override of $m$ (\ref{correctMemberOverrides}).
+}
+
+\subsection{Mixin Declaration}
+\LMLabel{mixinDeclaration}
+
+\LMHash{}%
+A mixin defines zero or more \IndexCustom{mixin member declarations}{mixin!member declaration},
+zero or more \IndexCustom{required superinterfaces}{mixin!required superinterface},
+one \IndexCustom{combined superinterface}{mixin!combined superinterface},
+and zero or more \IndexCustom{implemented interfaces}{mixin!implemented interface}.
+
+\LMHash{}%
+The mixin derived from a class declaration:
+\begin{normativeDartCode}
+\ABSTRACT? \CLASS{} $X$ \IMPLEMENTS{} $I_1$, \ldots{}, $I_k$ \{
+  \metavar{members}
+\}
+\end{normativeDartCode}
+has \code{Object} as required superinterface
+and combined superinterface,
+$I_1$, \ldots, $I_k$ as implemented interfaces,
+and the instance members of \metavar{members} as mixin member declarations.
+If $X$ is generic, so is the mixin.
+
+\LMHash{}%
+A mixin declaration introduces a mixin and provides a scope
+for static member declarations.
+
+\begin{grammar}
+<mixinDeclaration> ::= <metadata> \MIXIN{} <identifier> <typeParameters>?
+  \gnewline{} (\ON{} <typeNotVoidList>)? <interfaces>?
+  \gnewline{} `\{' (<metadata> <classMemberDefinition>)* `\}'
+\end{grammar}
+
+\LMHash{}
+It is a compile-time error to declare a constructor in a mixin-declaration.
+
+\LMHash{}
+A mixin declaration with no \code{\ON{}} clause is equivalent
+to one with the clause \code{\ON{} Object}.
+
+\LMHash{}
+Let $M$ be a \MIXIN{} declaration of the form
+\begin{normativeDartCode}
+\MIXIN{} $N$<\TypeParametersStd> \ON{} \List{T}{1}{n} \IMPLEMENTS{} \List{I}{1}{k} \{
+  \metavar{members}
+\}
+\end{normativeDartCode}
+It is a compile-time error if any of the types $T_1$ through $T_n$
+or $I_1$ through $I_k$ is
+a type variable (\ref{generics}),
+a function type (\ref{functionTypes}),
+a type alias not denoting a class (\ref{typedef}),
+an enumerated type (\ref{enums}),
+a deferred type (\ref{staticTypes}),
+type \DYNAMIC{} (\ref{typeDynamic}),
+type \VOID{} (\ref{typeVoid}),
+or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
+
+\LMHash{}%
+Let $M_S$ be the interface declared by the class declaration
+\begin{normativeDartCode}
+abstract \CLASS{} $M_{super}$<$P_1$, \ldots{}, $P_m$> implements $T_1$, $\dots{}$, $T_n$ \{\}
+\end{normativeDartCode}
+where $M_{super}$ is a fresh name.
+It is a compile-time error for the mixin declaration if the $M_S$
+class declaration would cause a compile-time error,
+\commentary{
+that is, if any member is declared by more than one declared superinterface,
+and there is not a most specific signature for that member among the super
+interfaces}.
+The interface $M_S$ is called the
+\Index{superinvocation interface} of the mixin declaration $M$.
+\commentary{
+If the mixin declaration $M$ has only one declared superinterface, $T_1$,
+then the superinvocation interface $M_{super}$ has exactly the same members
+as the interface $T_1$.}
+
+\LMHash{}
+Let $M_I$ be the interface that would be defined by the class declaration
+\begin{normativeDartCode}
+\ABSTRACT{} \CLASS{} $N$<\TypeParametersStd> \IMPLEMENTS{} \List{T}{1}{n}, \List{I}{1}{k} \{
+  $\metavar{members}'$
+\}
+\end{normativeDartCode}
+where $\metavar{members}'$ are the member declarations of
+the mixin declaration $M$ except that all superinvocations are treated
+as if \SUPER{} was a valid expression with static type $M_S$.
+It is a compile-time error for the mixin $M$ if this $N$ class
+declaration would cause a compile-time error, \commentary{that is, if the
+required superinterfaces, the implemented interfaces and the declarations do not
+define a consistent interface, if any member declaration contains a
+compile-time error other than a super-invocation, or if a super-invocation
+is not valid against the interface $M_S$}.
+The interface introduced by the mixin declaration $M$ has the same member
+signatures and superinterfaces as $M_I$.
+
+\LMHash{}%
+The mixin declaration $M$ introduces a mixin
+with the \NoIndex{required superinterface}s $T_1$, \ldots{}, $T_n$,
+the \NoIndex{combined superinterface} $M_S$,
+\NoIndex{implemented interface}s $I_1$, \ldots{}, $I_k$
+and the instance members declared in $M$ as \Index{mixin member declarations}.
+
+\subsection{Mixin Application}
+\LMLabel{mixinApplication}
+
+\LMHash{}%
+A mixin may be applied to a superclass, yielding a new class.
+
+\LMHash{}%
+Let $S$ be a class,
+$M$ be a mixin with \NoIndex{required superinterface}s $T_1$, \ldots, $T_n$,
+\NoIndex{combined superinterface} $M_S$,
+\NoIndex{implemented interfaces} $I_1$, \ldots{}, $I_k$ and
+\metavar{members} as \NoIndex{mixin member declarations},
+and let $N$ be a name.
+
+\LMHash{}%
+It is a compile-time error to apply $M$ to $S$ if $S$ does not implement,
+directly or indirectly, all of $T_1$, \ldots, $T_n$.
+It is a compile-time error if any of \metavar{members} contains a
+super-invocation of a member $m$ \commentary{(for example \code{super.foo},
+\code{super + 2}, or \code{super[1] = 2})}, and $S$ does not have a concrete
+implementation of $m$ which is a valid override of the member $m$ in
+the interface $M_S$. \rationale{We treat super-invocations in mixins as
+interface invocations on the combined superinterface, so we require the
+superclass of a mixin application to have valid implementations of those
+interface members that are actually super-invoked.}
+
+\LMHash{}%
+The mixin application of $M$ to $S$ with name $N$ introduces a new
+class, $C$, with name $N$, superclass $S$,
+implemented interface $I_1$, \ldots{}, $I_k$
+and \metavar{members} as instance members.
+The class $C$ has no static members.
+If $S$ declares any generative constructors, then the application
+introduces generative constructors on $C$ as follows:
 
 \LMHash{}%
 Let $L_C$ be the library containing the mixin application.
 \commentary{That is, the library containing the clause \code{$S$ \WITH{} $M$}
-or the clause \code{$S_0$ \WITH{} $M_1$, \ldots,\ $M_k$, $M$}.}
+or the clause \code{$S_0$ \WITH{} $M_1$, \ldots,\ $M_k$, $M$} giving rise
+to the mixin application.}
 
-Let $N_C$ be the name of the mixin application class $C$,
-let $S$ be the superclass of $C$, and let $S_N$ be the name of $S$.
+Let $S_N$ be the name of $S$.
 
 For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, $\ldots$, $T_{k}$ $a_{k}$)} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
 
@@ -4283,10 +4527,10 @@
 
 \noindent
 where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$,
-which denote the superclass, by $N_C$, and $\SUPER_q$ is obtained from $S_q$ by
+which denote the superclass, by $N$, and $\SUPER_q$ is obtained from $S_q$ by
 replacing occurrences of $S_N$ which denote the superclass by \SUPER{}.
-If $S_q$ is a generative const constructor, and $M$ does not declare any
-fields, $C_q$ is also a const constructor.
+If $S_q$ is a generative const constructor, and $C$ does not declare any
+instance variables, $C_q$ is also a const constructor.
 
 \LMHash{}%
 For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, [$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+p}$ $a_{k+p}$ = $d_p$])} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
@@ -4298,13 +4542,13 @@
 
 \noindent
 where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$,
-which denote the superclass, by $N_C$,
+which denote the superclass, by $N$,
 $\SUPER_q$ is obtained from $S_q$ by replacing occurrences of $S_N$
 which denote the superclass by \SUPER{},
 and $d'_i$, $i \in 1..p$, is a constant expression evaluating
 to the same value as $d_i$.
-If $S_q$ is a generative const constructor, and $M$ does not declare any
-fields, $C_q$ is also a const constructor.
+If $S_q$ is a generative const constructor, and $MC$ does not declare any
+instance variables, $C_q$ is also a const constructor.
 
 \LMHash{}%
 For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, \{$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+n}$ $a_{k+n}$ = $d_n$\})} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
@@ -4316,104 +4560,13 @@
 
 \noindent
 where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$
-which denote the superclass by $N_C$,
+which denote the superclass by $N$,
 $\SUPER_q$ is obtained from $S_q$ by replacing occurrences of $S_N$
 which denote the superclass by \SUPER{},
 and $d'_i$, $i \in 1..n$, is a constant expression evaluating to the same value as $d_i$.
 If $S_q$ is a generative const constructor, and $M$ does not declare any
 fields, $C_q$ is also a const constructor.
 
-\LMHash{}%
-If the mixin application class declares interfaces, the resulting class also implements those interfaces.
-
-\LMHash{}%
-It is a compile-time error if $S$ is an enumerated type (\ref{enums}) or a malformed type.
-It is a compile-time error if $M$ (respectively, any of $M_1, \ldots, M_k$) is an enumerated type (\ref{enums}) or a malformed type.
-It is a compile-time error if a well formed mixin cannot be derived from $M$ (respectively, from each of $M_1, \ldots, M_k$).
-
-\commentary{%
-Note that \VOID{} is a reserved word,
-which implies that the same restrictions apply for the type \VOID,
-and similar restrictions are specified for other types like
-\code{Null} (\ref{null}) and
-\code{String} (\ref{strings}).%
-}
-
-\LMHash{}%
-Let $K$ be a class declaration with the same constructors, superclass and interfaces as $C$, and the instance members declared by $M$ (respectively $M_1, \ldots, M_k$).
-It is a compile-time error if the declaration of $K$ would cause a compile-time error.
-
-\commentary{
-If, for example,
-$M$ declares an instance member $im$ whose type is at odds with the type of a member of the same name in $S$,
-this will result in a compile-time error just as if we had defined $K$ by means of an ordinary class declaration extending $S$, with a body that included $im$.
-}
-
-\LMHash{}%
-The effect of a class definition of the form \code{\CLASS{} $C$ = $M$; } or the form \code{\CLASS{} $C<T_1, \ldots,\ T_n>$ = $M$; } in library $L$ is to introduce the name $C$ into the scope of $L$, bound to the class (\ref{classes}) defined by the mixin application $M$ for the name $C$.
-The name of the class is also set to $C$.
-If{}f the class is prefixed by the built-in identifier \ABSTRACT{}, the class being defined is an abstract class.
-
-\LMHash{}%
-Let $M_A$ be a mixin derived from a class $M$ with direct superclass $S_{static}$, e.g., as defined by the class declaration \code{class M extends S$_{static}$ \{ \ldots \}}.
-
-\LMHash{}%
-Let $A$ be an application of $M_A$.
-It is a compile-time error if the superclass of $A$ is not a subtype of $S_{static}$.
-
-\LMHash{}%
-Let $C$ be a class declaration that includes $M_A$ in a with clause.
-It is a compile-time error if $C$ does not implement, directly or indirectly, all the direct superinterfaces of $M$.
-
-
-\subsection{Mixin Composition}
-\LMLabel{mixinComposition}
-
-\rationale{
-Dart does not directly support mixin composition, but the concept is useful when defining how the superclass of a class with a mixin clause is created.
-}
-
-\LMHash{}%
-The \Index{composition of two mixins},
-\code{$M_1$<$T_1, \ldots, T_{k_{M_1}}$>} and
-\code{$M_2$<$U_1, \ldots, U_{k_{M_2}}$>}, written
-\code{$M_1$<$T_1, \ldots, T_{k_{M_1}}$>$ * M_2$<$U_1, \ldots, U_{k_{M_2}}$>}
-defines an anonymous mixin such that for any class
-\code{$S$<$V_1, \ldots, V_{k_S}$>},
-the application of
-
-\code{$M_1$<$T_1, \ldots, T_{k_{M_1}}$> $*$ $M_2$<$U_1, \ldots, U_{k_{M_2}}$>}
-
-to \code{$S$<$V_1, \ldots, V_{k_S}$>} for the name $C$ is equivalent to
-
-\begin{normativeDartCode}
-\ABSTRACT{} \CLASS{} $C<T_1, \ldots, T_{k_{M_1}}, U_1, \ldots, U_{k_{M_2}}, V_1, \ldots, V_{k_S}> = $
-      $Id_2<U_1, \ldots, U_{k_{M_2}}, V_1 \ldots V_{k_S}>$ \WITH{} $M_1 <T_1, \ldots, T_{k_{M_1}}>$;
-\end{normativeDartCode}
-
-where $Id_2$ denotes
-
-\begin{normativeDartCode}
-\ABSTRACT{} \CLASS{} $Id_2<U_1, \ldots, U_{k_{M_2}}, V_1, \ldots, V_{k_S}> =$
-                         $S<V_1, \ldots, V_{k_S}>$ \WITH{} $M_2<U_1, \ldots, U_{k_{M_2}}>$;
-\end{normativeDartCode}
-
-and $Id_2$ is a unique identifier that does not exist anywhere in the program.
-
-\rationale{
-The intermediate classes produced by mixin composition are regarded as abstract because they cannot be instantiated independently.
-They are only introduced as anonymous superclasses of ordinary class declarations and mixin applications.
-Consequently, no errors are raised if a mixin composition includes abstract members, or incompletely implements an interface.
-}
-
-\LMHash{}%
-Mixin composition is associative.
-
-\commentary{
-Note that any subset of $M_1$, $M_2$ and $S$ may or may not be generic.
-For any non-generic declaration, the corresponding type parameters may be elided, and if no type parameters remain in the derived declarations $C$ and/or $Id_2$ then the those declarations need not be generic either.
-}
-
 
 \section{Enums}
 \LMLabel{enums}
@@ -4513,7 +4666,7 @@
 $T$ is a type,
 and \code{$S$?} is a type or the empty string.
 Let $S'$ be \code{$S$?} if it is a type, otherwise let $S'$ be \DYNAMIC.
-The associated function type of $D$, call it $F$, is, respectively:
+The associated type of $D$, call it $F$, is, respectively:
 
 \begin{itemize}
 \item $T$
@@ -4554,7 +4707,7 @@
 $[T_1/X_1, \ldots, T_s/X_s]F$.
 
 \commentary{%
-Note that the type alias syntax without \syntax{`='}
+Note that the type alias syntax without \lit{=}
 can only express function types,
 and it cannot express the type of a generic function.
 When such a type alias is generic,
@@ -4643,10 +4796,14 @@
 \LMHash{}%
 Type parameters are declared in the type parameter scope of a class or function.
 The type parameters of a generic $G$ are in scope in the bounds of all of the type parameters of $G$.
-The type parameters of a generic class declaration $G$ are also in scope in the \EXTENDS{} and \IMPLEMENTS{} clauses of $G$ (if these exist) and in the body of $G$.
-However, a type parameter of a generic class is considered to be a malformed type when referenced by a static member.
+The type parameters of a generic class declaration $G$ are also in scope in
+the \EXTENDS{} and \IMPLEMENTS{} clauses of $G$ (if these exist) and in the body of $G$.
 
-\commentary{
+\commentary{%
+However, a type parameter of a generic class
+is considered to be a malformed type
+when referenced by a static member
+(\ref{staticTypes}).
 The scopes associated with the type parameters of a generic function are described in (\ref{formalParameters}).
 }
 
@@ -5353,6 +5510,7 @@
 etc.
 }
 
+
 \subsubsection{The Instantiation to Bound Algorithm}
 \LMLabel{theInstantiationToBoundAlgorithm}
 
@@ -5811,7 +5969,7 @@
 \item $e_1$ evaluates to \FALSE{} and $e_2$ is a constant expression that evaluates to a value of type \code{bool}.
 \end{enumerate}
 
-\item An expression of the form \code{~$e_1$} is a potentially constant expression if $e_1$ is a potentially constant expression. It is further a constant expression if $e_1$ is a constant expression that evaluates to a value of type \code{int}.
+\item An expression of the form \code{\~{}$e_1$} is a potentially constant expression if $e_1$ is a potentially constant expression. It is further a constant expression if $e_1$ is a constant expression that evaluates to a value of type \code{int}.
 
 \item An expression of one of the forms \code{$e_1$\,\&\,$e_2$}, \code{$e_1$\,|\,$e_2$}, or \code{$e_1$\,\^\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if both $e_1$ and $e_2$ are constant expressions that both evaluate to values that are both instances of \code{int}, or that are both instances of \code{bool}.
 % The bool case is new in 2.1.
@@ -5858,17 +6016,28 @@
 
 \LMHash{}%
 % New in 2.1.
-A constant type expression is one of:
+A
+\Index{constant type expression}
+is one of:
 \begin{itemize}
-\item An simple or qualified identifier denoting a type declaration (a type alias, class or mixin declaration) that is not qualified by a deferred prefix,
-optionally followed by type arguments of the form
-\code{<$T_1$,\ \ldots,\ $T_n$>}
-where $T_1$, \ldots{}, $T_n$ are constant type expressions.
-\item A type of the form \code{FutureOr<$T$>} where $T$ is a constant type expression.
-\item A function type
-\code{$R$ Function<\metavar{typeParameters}>(\metavar{argumentTypes})}
-(where $R$ and \code{<\metavar{typeParameters}>} may be omitted)
-and where $R$, \metavar{typeParameters} and \metavar{argumentTypes} (if present) contain only constant type expressions.
+\item An simple or qualified identifier
+  denoting a type declaration (a type alias, class or mixin declaration)
+  that is not qualified by a deferred prefix,
+  optionally followed by type arguments of the form
+  \code{<$T_1$,\ \ldots,\ $T_n$>}
+  where $T_1$, \ldots{}, $T_n$ are constant type expressions.
+\item A type of the form \code{FutureOr<$T$>}
+  where $T$ is a constant type expression.
+\item
+  %% TODO(eernst): This does not allow for type variables introduced by
+  %% the type itself. `Function<X>(X)` could be a constant type expression,
+  %% but that is not covered by the current rules: `X` is a type variable,
+  %% and they are never allowed.
+  A function type
+  \code{$R$ Function<\metavar{typeParameters}>(\metavar{argumentTypes})}
+  (where $R$ and \code{<\metavar{typeParameters}>} may be omitted)
+  and where $R$, \metavar{typeParameters} and \metavar{argumentTypes}
+  (if present) contain only constant type expressions.
 \item The type \VOID{}.
 \item The type \DYNAMIC{}.
 \end{itemize}
@@ -5992,11 +6161,13 @@
 
 \LMHash{}%
 The null object is the sole instance of the built-in class \code{Null}.
-Attempting to instantiate \code{Null} causes a run-time error.
+% The following can be a consequence of the declaration of `Null`,
+% but we don't spell that out, we just require that it is an error.
+Attempting to instantiate \code{Null} causes a compile-time error.
 It is a compile-time error for a class to extend, mix in or implement \code{Null}.
 The \code{Null} class extends the \code{Object} class and declares no methods except those also declared by \code{Object}.
-\commentary{As such, it does not override the \code{==} operator inherited
-from the \code{Object} class.}
+In particular, the \code{Null} class does not override the \lit{==} operator
+inherited from the \code{Object} class.
 
 \LMHash{}%
 The static type of \NULL{} is the \code{Null} type.
@@ -6111,7 +6282,8 @@
 It is a compile-time error for any class other than \code{int} and \code{double} to extend, mix in or implement \code{num}.
 
 \LMHash{}%
-The instances of \code{int} and \code{double} all override the \code{==} operator inherited from the \code{Object} class.
+The instances of \code{int} and \code{double} all override the \lit{==} operator inherited from the \code{Object} class.
+
 
 \subsection{Booleans}
 \LMLabel{booleans}
@@ -6132,10 +6304,11 @@
 Both \NoIndex{true} and \NoIndex{false} are instances of
 the built-in class \code{bool},
 and there are no other objects that implement \code{bool}.
-It is a compile-time error for a class to extend, mix in or implement \code{bool}.
+It is a compile-time error for a class to
+extend, mix in or implement \code{bool}.
 
 \LMHash{}%
-The \code{bool} class does not override the \code{==} operator inherited from
+The \code{bool} class does not override the \lit{==} operator inherited from
 the \code{Object} class.
 
 \LMHash{}%
@@ -6251,8 +6424,15 @@
 \end{grammar}
 
 \LMHash{}%
-Multiline strings are delimited by either matching triples of single quotes or matching triples of double quotes.
-If the first line of a multiline string consists solely of the whitespace characters defined by the production \synt{WHITESPACE} (\ref{lexicalRules}), possibly prefixed by \syntax{`\\'}, then that line is ignored, including the line break at its end.
+Multiline strings are delimited by either
+matching triples of single quotes or
+matching triples of double quotes.
+If the first line of a multiline string consists solely of
+the whitespace characters defined by the production \synt{WHITESPACE}
+(\ref{lexicalRules}),
+possibly prefixed by \syntax{`\\'},
+then that line is ignored,
+including the line break at its end.
 
 \rationale{
 The idea is to ignore a whitespace-only first line of a multiline string, where whitespace is defined as tabs, spaces and the final line break.
@@ -6267,42 +6447,60 @@
 Strings support escape sequences for special characters.
 The escapes are:
 \begin{itemize}
-\item \syntax{`\\n'} for newline, equivalent to \syntax{`\\x0A'}.
-\item \syntax{`\\r'} for carriage return, equivalent to \syntax{`\\x0D'}.
-\item \syntax{`\\f'} for form feed, equivalent to \syntax{`\\x0C'}.
-\item \syntax{`\\b'} for backspace, equivalent to \syntax{`\\x08'}.
-\item \syntax{`\\t'} for tab, equivalent to \syntax{`\\x09'}.
-\item \syntax{`\\v'} for vertical tab, equivalent to \syntax{`\\x0B'}.
-\item \syntax{`\\x' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$}, equivalent to
+\item
+  \syntax{`\\n'} for newline, equivalent to \syntax{`\\x0A'}.
+\item
+  \syntax{`\\r'} for carriage return, equivalent to \syntax{`\\x0D'}.
+\item
+  \syntax{`\\f'} for form feed, equivalent to \syntax{`\\x0C'}.
+\item
+  \syntax{`\\b'} for backspace, equivalent to \syntax{`\\x08'}.
+\item
+  \syntax{`\\t'} for tab, equivalent to \syntax{`\\x09'}.
+\item
+  \syntax{`\\v'} for vertical tab, equivalent to \syntax{`\\x0B'}.
+\item
+  \syntax{`\\x' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$}, equivalent to
 
-\syntax{`\\u{' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ `}'}.
-\item \syntax{`\\u' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ <HEX\_DIGIT>$_3$ <HEX\_DIGIT>$_4$},
-equivalent to
+  \syntax{`\\u{' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ `}'}.
+\item
+  \syntax{`\\u' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ <HEX\_DIGIT>$_3$ <HEX\_DIGIT>$_4$},
+  equivalent to
 
-\noindent
-\syntax{`\\u{' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ <HEX\_DIGIT>$_3$ <HEX\_DIGIT>$_4$ `}'}.
-\item \syntax{`\\u{' <HEX\_DIGIT\_SEQUENCE> `}'} is the Unicode code point represented by the
-\syntax{<HEX\_DIGIT\_SEQUENCE>}.
-It is a compile-time error if the value of the
-\syntax{<HEX\_DIGIT\_SEQUENCE>}
-is not a valid Unicode code point.
-\item \syntax{`$'} indicating the beginning of an interpolated expression.
-\item Otherwise, \syntax{`\\'$k$} indicates the character $k$ for any $k$ not in
-\syntax{$\{$`n', `r', `f', `b', `t', `v', `x', `u'$\}$}.
+  \noindent
+  \syntax{`\\u{' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ <HEX\_DIGIT>$_3$ <HEX\_DIGIT>$_4$ `}'}.
+\item
+  \syntax{`\\u{' <HEX\_DIGIT\_SEQUENCE> `}'} is
+  the Unicode code point represented by the
+  \syntax{<HEX\_DIGIT\_SEQUENCE>}.
+  It is a compile-time error if the value of the
+  \syntax{<HEX\_DIGIT\_SEQUENCE>}
+  is not a valid Unicode code point.
+\item
+  \lit{\$} indicating the beginning of an interpolated expression.
+\item
+  Otherwise, \syntax{`\\$k$'} indicates the character $k$ for
+  any $k$ not in \syntax{$\{$`n', `r', `f', `b', `t', `v', `x', `u'$\}$}.
 \end{itemize}
 
 \LMHash{}%
-Any string may be prefixed with the character \syntax{`r'},
+Any string may be prefixed with the character \lit{r},
 indicating that it is a \Index{raw string},
 in which case no escapes or interpolations are recognized.
 
 \LMHash{}%
-Line breaks in a multiline string are represented by the \syntax{<NEWLINE>} production.
+Line breaks in a multiline string are represented by
+the \syntax{<NEWLINE>} production.
 A line break introduces a single newline character into the string value.
 
 \LMHash{}%
-It is a compile-time error if a non-raw string literal contains a character sequence of the form \syntax{`\\x'} that is not followed by a sequence of two hexadecimal digits.
-It is a compile-time error if a non-raw string literal contains a character sequence of the form \syntax{`\\u'} that is not followed by either a sequence of four hexadecimal digits, or by curly brace delimited sequence of hexadecimal digits.
+It is a compile-time error if a non-raw string literal contains
+a character sequence of the form \syntax{`\\x'} that is not followed by
+a sequence of two hexadecimal digits.
+It is a compile-time error if a non-raw string literal contains
+a character sequence of the form \syntax{`\\u'} that is not followed by
+either a sequence of four hexadecimal digits,
+or by curly brace delimited sequence of hexadecimal digits.
 
 \begin{grammar}
 <stringContentDQ> ::= \~{}( `\\' | `"' | `$' | <NEWLINE> )
@@ -6328,8 +6526,9 @@
 
 \LMHash{}%
 All string literals evaluate to instances of the built-in class \code{String}.
-It is a compile-time error for a class to extend, mix in or implement \code{String}.
-The \code{String} class overrides the \code{==} operator inherited from
+It is a compile-time error for a class to
+extend, mix in or implement \code{String}.
+The \code{String} class overrides the \lit{==} operator inherited from
 the \code{Object} class.
 The static type of a string literal is \code{String}.
 
@@ -6338,7 +6537,10 @@
 \LMLabel{stringInterpolation}
 
 \LMHash{}%
-It is possible to embed expressions within non-raw string literals, such that these expressions are evaluated, and the resulting values are converted into strings and concatenated with the enclosing string.
+It is possible to embed expressions within non-raw string literals,
+such that these expressions are evaluated,
+and the resulting values are converted into strings and
+concatenated with the enclosing string.
 This process is known as \Index{string interpolation}.
 
 \begin{grammar}
@@ -6347,14 +6549,17 @@
 \end{grammar}
 
 \commentary{
-The reader will note that the expression inside the interpolation could itself include strings, which could again be interpolated recursively.
+The reader will note that the expression inside the interpolation
+could itself include strings,
+which could again be interpolated recursively.
 }
 
 \LMHash{}%
-An unescaped \syntax{`$'} character in a string signifies the beginning of an interpolated expression.
-The \syntax{`$'} sign may be followed by either:
+An unescaped \lit{\$} character in a string signifies
+the beginning of an interpolated expression.
+The \lit{\$} sign may be followed by either:
 \begin{itemize}
-\item A single identifier \id{} that must not contain the \syntax{`$'} character.
+\item A single identifier \id{} that does not contain the \lit{\$} character.
 \item An expression $e$ delimited by curly braces.
 \end{itemize}
 
@@ -6386,13 +6591,13 @@
 
 \LMHash{}%
 A symbol literal \code{\#\id} where \id{} is an identifier
-that does not begin with an underscore ('\code{\_}'),
+that does not begin with an underscore (`\code{\_}'),
 evaluates to an instance of \code{Symbol} representing the identifier \id.
 All occurrences of \code{\#\id} evaluate to the same instance
 \commentary{(symbol instances are canonicalized)},
 and no other symbol literals evaluate to that \code{Symbol} instance
 or to a \code{Symbol} instance that is equal
-(according to the \code{==} operator \ref{equality}) to that instance.
+(according to the \lit{==} operator \ref{equality}) to that instance.
 
 \LMHash{}%
 A symbol literal \code{\#$\id.\id_2\ldots\id_n$}
@@ -6401,7 +6606,7 @@
 All occurrences of \code{\#$\id.\id_2\ldots\id_n$} with the same sequence of identifiers
 evaluate to the same instance,
 and no other symbol literals evaluate to that \code{Symbol} instance
-or to a \code{Symbol} instance that is \code{==} to that instance.
+or to a \code{Symbol} instance that is \lit{==} to that instance.
 \commentary{This kind of symbol literal denotes the name of a library declaration. Library names are not subject to library privacy, even
 if some of its identifiers begin with an underscore.}
 
@@ -6410,18 +6615,18 @@
 representing that particular operator name.
 All occurrences of \code{\#\metavar{operator}} evaluate to the same instance,
 and no other symbol literals evaluate to that \code{Symbol} instance
-or to a \code{Symbol} instance that is \code{==} to that instance.
+or to a \code{Symbol} instance that is \lit{==} to that instance.
 
 \LMHash{}%
 A symbol literal \code{\#\_\id}, evaluates to an instance of \code{Symbol}
 representing the private identifier \code{\_\id} of the containing library.
 All occurrences of \code{\#\_\id} \emph{in the same library} evaluate to the same instance,
 and no other symbol literals evaluate to that \code{Symbol} instance
-or to a \code{Symbol} instance that is \code{==} to that instance.
+or to a \code{Symbol} instance that is \lit{==} to that instance.
 
 \LMHash{}%
 The objects created by symbol literals all override
-the \code{==} operator inherited from the \code{Object} class.
+the \lit{==} operator inherited from the \code{Object} class.
 
 \rationale{
 One may well ask what is the motivation for introducing literal symbols? In some languages, symbols are canonicalized whereas strings are not.
@@ -6441,6 +6646,7 @@
 \LMHash{}%
 The static type of a symbol literal is \code{Symbol}.
 
+
 \subsection{Lists}
 \LMLabel{lists}
 
@@ -6458,7 +6664,8 @@
 A list has an associated set of indices.
 An empty list has an empty set of indices.
 A non-empty list has the index set $\{0, \ldots, n - 1\}$ where $n$ is the size of the list.
-It is a run-time error to attempt to access a list using an index that is not a member of its set of indices.
+It is a dynamic error to attempt to access a list
+using an index that is not a member of its set of indices.
 
 \LMHash{}%
 If a list literal begins with the reserved word \CONST{}, it is a
@@ -6469,11 +6676,11 @@
 and it is evaluated at run time.
 Only run-time list literals can be mutated
 after they are created.
+% This error can occur because being constant is a dynamic property, here.
 Attempting to mutate a constant list literal will result in a dynamic error.
 
 \LMHash{}%
 It is a compile-time error if an element of a constant list literal is not a constant expression.
-% Need 'free': `const <Function(Function<X>(X))>[]` is OK, but `X` is not free.
 It is a compile-time error if the type argument of a constant list literal is
 not a constant type expression.
 \rationale{
@@ -6509,26 +6716,31 @@
 is evaluated as follows:
 \begin{itemize}
 \item
-First, the expressions $e_1, \ldots, e_n$ are evaluated in order they appear in the program, producing objects $o_1, \ldots, o_n$.
-\item A fresh instance (\ref{generativeConstructors}) $a$, of size $n$, whose class implements the built-in class
-\code{List<$E$>}
-is allocated.
+  First, the expressions $e_1, \ldots, e_n$ are evaluated
+  in order they appear in the program,
+  producing objects $o_1, \ldots, o_n$.
 \item
-The operator \syntax{`[]='} is invoked on $a$ with first argument $i$ and second argument
-%The $i$th element of $a$ is set to
-$o_{i+1}, 0 \le i < n$.
+  A fresh instance (\ref{generativeConstructors}) $a$, of size $n$,
+  whose class implements the built-in class \code{List<$E$>}
+  is allocated.
 \item
-The result of the evaluation is $a$.
+  The operator \lit{[]=} is invoked on $a$ with
+  first argument $i$ and second argument
+  $o_{i+1}, 0 \le i < n$.
+\item
+  The result of the evaluation is $a$.
 \end{itemize}
 
 \LMHash{}%
 The objects created by list literals do not override
-the \code{==} operator inherited from the \code{Object} class.
+the \lit{==} operator inherited from the \code{Object} class.
 
 \commentary{
-Note that this document does not specify an order in which the elements are set.
-This allows for parallel assignments into the list if an implementation so desires.
-The order can only be observed (and may not be relied upon):
+Note that this document does not specify an order
+in which the elements are set.
+This allows for parallel assignments into the list
+if an implementation so desires.
+The order can only be observed as follows (and may not be relied upon):
 if element $i$ is not a subtype of the element type of the list,
 a dynamic type error will occur when $a[i]$ is assigned $o_{i-1}$.
 }
@@ -6583,8 +6795,8 @@
 If $e$ has three or more type arguments, it is a compile-time error.
 If $e$ has \emph{no} type arguments,
 then let $S$ be the static context type of the literal.
-If $\basetype{S}$ (\ref{typeFutureOr}) is a subtype of \code{Iterable<Object>}
-and $\basetype{S}$ is not a subtype of \code{Map<Object, Object>},
+If $\futureOrBase{S}$ (\ref{typeFutureOr}) is a subtype of \code{Iterable<Object>}
+and $\futureOrBase{S}$ is not a subtype of \code{Map<Object, Object>},
 then $e$ is set literal,
 and otherwise it is a map literal.
 A map literal derived from \synt{setOrMapLiteral}
@@ -6606,24 +6818,20 @@
 \IndexCustom{run-time map literal}{literal!map!run-time}
 and it is evaluated at run time.
 Only run-time map literals can be mutated after they are created.
+% This error can occur because being constant is a dynamic property, here.
 Attempting to mutate a constant map literal will result in a dynamic error.
 
 \LMHash{}%
-It is a compile-time error if either a key or a value of an entry in a constant map literal is not a constant expression.
-It is a compile-time error if the key of an entry in a constant map literal is an instance of
-a class that has a concrete operator \syntax{`=='} declaration different from the one in \code{Object},
-unless the key is a string or an integer,
-the key expression evaluates to an instance of the built-in
-class \code{Symbol} which was originally obtained by evaluation of a
-literal symbol or
-a constant invocation of a constructor of the \code{Symbol} class,
-or to an object implementing the built-in class \code{Type}
-which was originally obtained by evaluating a constant type literal
-(\ref{dynamicTypeSystem}).
-% Needs 'free': `const <int, Function(Function<X>(X))>{}` is OK, but
-% `X` is not free.
+It is a compile-time error if
+either a key or a value of an entry in a constant map literal
+is not a constant expression.
+It is a compile-time error if
+the operator \lit{==} of the key of an entry in a constant map literal
+is not primitive
+(\ref{theOperatorEqualsEquals}).
 It is a compile-time error if a type argument of a constant map literal
-is not a constant type expression \ref{constants}.
+is not a constant type expression
+(\ref{constants}).
 
 \LMHash{}%
 The value of a constant map literal
@@ -6651,7 +6859,7 @@
 
 \LMHash{}%
 It is a compile-time error if two keys of a constant map literal are equal
-according to their \code{==} operator (\ref{equality}).
+according to their \lit{==} operator (\ref{equality}).
 
 \LMHash{}%
 A run-time map literal
@@ -6659,21 +6867,25 @@
 is evaluated as follows:
 \begin{itemize}
 \item
-For each $i \in 1 .. n$ in numeric order,
-first the expression $k_i$ is evaluated producing object $u_i$,
-and then $e_i$ is evaluated producing object $o_i$.
-This produces all the objects $u_1, o_1, \ldots, u_n, o_n$.
-\item A fresh instance (\ref{generativeConstructors}) $m$
-whose class implements the built-in class \code{Map<$K, V$>}, is allocated.
+  For each $i \in 1 .. n$ in numeric order,
+  first the expression $k_i$ is evaluated producing object $u_i$,
+  and then $e_i$ is evaluated producing object $o_i$.
+  This produces all the objects $u_1, o_1, \ldots, u_n, o_n$.
 \item
-The operator \syntax{`[]='} is invoked on $m$ with first argument $u_i$ and second argument $o_i$ for each $i \in 1 .. n$.
+  A fresh instance (\ref{generativeConstructors}) $m$
+  whose class implements the built-in class \code{Map<$K, V$>},
+  is allocated.
 \item
-The result of the evaluation is $m$.
+  The operator \lit{[]=} is invoked on $m$
+  with first argument $u_i$ and second argument $o_i$
+  for each $i \in 1 .. n$.
+\item
+  The result of the evaluation is $m$.
 \end{itemize}
 
 \LMHash{}%
 The objects created by map literals do not override
-the \code{==} operator inherited from the \code{Object} class.
+the \lit{==} operator inherited from the \code{Object} class.
 
 \LMHash{}%
 A run-time map literal
@@ -6683,11 +6895,13 @@
 \code{<\DYNAMIC{}, \DYNAMIC{}>\{$k_1:e_1, \ldots, k_n:e_n$\}}.
 
 \LMHash{}%
-A map literal is ordered: iterating over the keys and/or values of the maps always happens in the
- order the keys appeared in the source code.
+A map literal is ordered:
+iterating over the keys and/or values of the maps
+always happens in the order the keys appeared in the source code.
 
 \commentary{
-Of course, if a key repeats, the order is defined by first occurrence, but the value is defined by the last.
+Of course, if a key repeats, the order is defined by first occurrence,
+but the value is defined by the last.
 }
 
 \LMHash{}%
@@ -6740,24 +6954,22 @@
 \IndexCustom{run-time set literal}{literal!set!run-time}
 and it is evaluated at run time.
 Only run-time set literals can be mutated after they are created.
+% This error can occur because being constant is a dynamic property, here.
 Attempting to mutate a constant set literal will result in a dynamic error.
 
 \LMHash{}%
-It is a compile-time error if an element expression in a constant set literal is not a constant expression.
-It is a compile-time error if the element object in a constant set literal is an instance of
-a class that has a concrete operator \syntax{`=='} declaration different from the one in \code{Object},
-unless the element is a string or an integer,
-the element expression evaluates to an instance of the built-in
-class \code{Symbol} which was originally obtained by evaluation of a
-literal symbol or
-a constant invocation of a constructor of the \code{Symbol} class,
-or to an object implementing the built-in class \code{Type}
-which was originally obtained by evaluating a constant type literal
-(\ref{dynamicTypeSystem}).
+It is a compile-time error if an element expression in a constant set literal
+is not a constant expression.
+It is a compile-time error if
+the operator \lit{==} of an element expression in a constant map literal
+is not primitive
+(\ref{theOperatorEqualsEquals}).
 It is a compile-time error if the type argument of a constant set literal
-is not a constant type expression \ref{constants}.
+is not a constant type expression
+(\ref{constants}).
 It is a compile-time error if two elements of a constant set literal are equal
-according to their \code{==} operator (\ref{equality}).
+according to their \lit{==} operator
+(\ref{equality}).
 
 \LMHash{}%
 The value of a constant set literal with element expressions
@@ -6801,7 +7013,7 @@
 
 \LMHash{}%
 The objects created by set literals do not override
-the \code{==} operator inherited from the \code{Object} class.
+the \lit{==} operator inherited from the \code{Object} class.
 
 \LMHash{}%
 A set literal is ordered: iterating over the elements of the sets
@@ -6819,6 +7031,7 @@
 is
 \code{Set<$E$>}.
 
+
 \subsection{Throw}
 \LMLabel{throw}
 
@@ -7191,9 +7404,7 @@
 \code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
 
 \noindent
-is malformed (\ref{staticTypes}),
-is malbounded (\ref{parameterizedTypes}),
-or is an enumerated type (\ref{enums}).
+is an enumerated type (\ref{enums}).
 
 
 \subsubsection{New}
@@ -7307,6 +7518,7 @@
 
 \noindent
 \commentary{Note that the non-generic case is covered by letting $m = 0$.}
+% This error can occur due to an implicit cast.
 If for any
 $j \in 1 .. n + k$
 the run-time type of $o_j$ is not a subtype of
@@ -7315,7 +7527,10 @@
 
 \LMHash{}%
 \Case{Non-loaded deferred constructors}
-If $T$ is a deferred type with prefix $p$, then if $p$ has not been successfully loaded, a dynamic error occurs.
+% This error can occur because being-loaded is a dynamic property.
+If $T$ is a deferred type with prefix $p$,
+then if $p$ has not been successfully loaded,
+a dynamic error occurs.
 \EndCase
 
 \LMHash{}%
@@ -7582,7 +7797,10 @@
 
 \LMHash{}%
 An isolate's memory is finite, as is the space available to its thread's call stack.
-It is possible for a running isolate to exhaust its memory or stack, resulting in a run-time error that cannot be effectively caught, which will force the isolate to be suspended.
+% This error can occur because memory usage is a dynamic property.
+It is possible for a running isolate to exhaust its memory or stack,
+resulting in a dynamic error that cannot be effectively caught,
+which will force the isolate to be suspended.
 
 \commentary{
 As discussed in section \ref{errorsAndWarnings}, the handling of a suspended isolate is the responsibility of the embedder.
@@ -7748,10 +7966,13 @@
 \end{grammar}
 
 \LMHash{}%
-Argument lists allow an optional trailing comma after the last argument (\syntax{`,'?}).
-An argument list with such a trailing comma is equivalent in all ways to the same parameter list without the trailing comma.
+Argument lists allow an optional trailing comma after the last argument
+(\syntax{`,'?}).
+An argument list with such a trailing comma is equivalent in all ways to
+the same parameter list without the trailing comma.
 All argument lists in this specification are shown without a trailing comma,
-but the rules and semantics apply equally to the corresponding argument list with a trailing comma.
+but the rules and semantics apply equally to
+the corresponding argument list with a trailing comma.
 
 \LMHash{}%
 Let $L$ be an argument list of the form
@@ -7771,15 +7992,18 @@
 \code{($T_1\ x_1 \ldots,\ T_n\ x_n,\ $[$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$])}
 
 \noindent
-where each parameter may be marked \COVARIANT{} (\commentary{not shown, but allowed}).
+where each parameter may be marked \COVARIANT{}
+(\commentary{not shown, but allowed}).
 
 \LMHash{}%
 We say that $\argumentList{S}$ is
 a \Index{subtype match} for $\parameterList{P}$
-if{}f $p = 0$, $n \leq m \leq n+k$, and $S_i$ is a subtype of $T_i$ for all $i \in 1 .. m$.
+if{}f $p = 0$, $n \leq m \leq n+k$, and $S_i$ is
+a subtype of $T_i$ for all $i \in 1 .. m$.
 We say that $\argumentList{S}$ is
 an \Index{assignable match} for $\parameterList{P}$
-if{}f $p = 0$, $n \leq m \leq n+k$, and $S_i$ is assignable to $T_i$ for all $i \in 1 .. m$.
+if{}f $p = 0$, $n \leq m \leq n+k$, and $S_i$ is
+assignable to $T_i$ for all $i \in 1 .. m$.
 
 \LMHash{}%
 Let $\argumentList{S}$ be the static argument list type
@@ -7792,7 +8016,8 @@
 \code{($T_1\ x_1 \ldots,\ T_n\ x_n,\ $\{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\})}
 
 \noindent
-where each parameter may be marked \COVARIANT{} (\commentary{not shown, but allowed}).
+where each parameter may be marked \COVARIANT{}
+(\commentary{not shown, but allowed}).
 
 \LMHash{}%
 We say that $\argumentList{S}$ is
@@ -8099,15 +8324,18 @@
 
 \LMHash{}%
 % Check the type arguments.
+% This error can occur due to covariance and due to dynamic invocation.
 It is a dynamic type error if $t_i$ is not a subtype of the actual bound
 (\ref{actualTypeOfADeclaration})
 of the $i$th type argument of $f$, for actual type arguments $t_1, \ldots, t_r$.
 % Check the types of positional arguments.
+% This error can occur due to implicit casts, covariance, and dynamic calls.
 It is a dynamic type error if $o_i$ is not the null object (\ref{null})
 and the actual type
 (\ref{actualTypeOfADeclaration})
 of $p_i$ is not a supertype of the dynamic type of $o_i, i \in 1 .. m$.
 % Check the types of named arguments.
+% This error can occur due to implicit casts, covariance, and dynamic calls.
 It is a dynamic type error if $o_{m+j}$ is
 not the null object and the actual type
 (\ref{actualTypeOfADeclaration})
@@ -8304,15 +8532,15 @@
 There does not exist a function type $F'$ which is a proper subtype of $F$
 such that $C$ is a subtype of $F'$.
 If $f$ denotes a static method or top-level function,
-class $C$ does not override the \code{==} operator
+class $C$ does not override the \lit{==} operator
 inherited from the \code{Object} class.
 
-\commentary{
+\commentary{%
 In other words, $C$ has the freedom to be a proper subtype of
 the function type that we can read off of the declaration of $f$
 because it may need to be a specific internal platform defined class,
 but $C$ does not have the freedom to be a subtype of
-a different and more special function type, and it cannot be \code{Null}.
+a different and more special function type, and it cannot be \code{Null}.%
 }
 
 \LMHash{}%
@@ -8326,6 +8554,217 @@
 as the invocation of $f$ would have yielded.
 
 
+\subsubsection{Generic Function Instantiation}
+\LMLabel{genericFunctionInstantiation}
+
+%% TODO(eernst): The specification of generic function instantiation relies
+%% on type inference in a different way than other mechanisms that we have
+%% specified, because it is impossible to claim that 'type inference is
+%% assumed to have taken place already' and then we just consider the
+%% program where the missing type arguments or type annotations have been
+%% added syntactically. Consequently, this section will probably need to be
+%% rewritten rather extensively when we add a specification of inference.
+
+\LMHash{}%
+Generic function instantiation is a mechanism that yields
+a non-generic function object,
+based on a reference to a generic function.
+
+\commentary{%
+It is a mechanism which is very similar to function closurization
+(\ref{functionClosurization}),
+but it only occurs in situations where
+a compile-time error would otherwise occur.
+}
+
+\rationale{%
+The essence of generic function instantiation
+is to allow for ``curried'' invocations,
+in the sense that a generic function can receive its actual
+type arguments separately during closurization
+(it must then receive \emph{all} type arguments, not just some of them),
+and that yields a non-generic function object.
+The type arguments are passed implicitly, based on type inference;
+a future version of Dart may allow for passing them explicitly.%
+}
+\commentary{Here is an example:}
+
+\begin{dartCode}
+X fg<X \EXTENDS{} num>(X x) => x;
+\\
+\CLASS{} A \{
+  \STATIC{} X fs<X \EXTENDS{} num>(X x) => x;
+\}
+\\
+\VOID{} main() \{
+  X fl<X \EXTENDS{} num>(X x) => x;
+  List<int \FUNCTION{}(int)> functions = [fg, A.fs, fl];
+\}
+\end{dartCode}
+
+\commentary{%
+\noindent
+Each function object stored in \code{functions}
+has dynamic type \code{int\,\,\FUNCTION(int)},
+and it is obtained by implicitly
+``passing the actual type argument \code{int}''
+to the corresponding generic function.
+}
+
+\LMHash{}%
+Let $f$ of the form
+\syntax{<identifier> ('.'~<identifier>\,('.'~<identifier>)?)?}~be
+an expression that denotes
+a declaration of a local function, a static method, or a top-level function,
+and let $G$ be the static type of $f$.
+Consider the situation where $G$ is a function type of the form
+\RawFunctionType{T_0}{X}{B}{s}{\metavar{parameters}}
+with $s > 0$
+(\commentary{that is, $G$ is a generic function type}),
+and the context type is a non-generic function type $F$.
+In this situation a compile-time error occurs
+(\ref{variables},
+\ref{functions},
+\ref{generativeConstructors},
+\ref{redirectingGenerativeConstructors},
+\ref{initializerLists},
+\ref{new},
+\ref{const},
+\ref{bindingActualsToFormals},
+\ref{assignment},
+\ref{localVariableDeclaration},
+\ref{switch},
+\ref{return},
+\ref{yieldEach}),
+except when the following step succeeds:
+
+\LMHash{}%
+\IndexCustom{Generic function type instantiation}{%
+  generic function type instantiation}:
+Type inference is applied to $G$ with context type $F$,
+and it succeeds, yielding the actual type argument list
+\List{T}{1}{s}.
+
+\commentary{%
+The generic function type instantiation fails
+in the case where type inference fails,
+in which case the above mentioned compile-time error occurs.
+It will be specified in a future version of this document
+how type inference computes \List{T}{1}{s}
+(\ref{overview}).
+}
+
+\LMHash{}%
+Otherwise, the generic function type instantiation succeeded.
+Let $F'$ denote the type
+$[T_1/X_1, \ldots, T_s/X_s]%
+(\FunctionTypeSimple{T_0}{\metavar{parameters}})$.
+\commentary{%
+Note that it is guaranteed that $F'$ is assignable to $F$,
+or inference would have failed.%
+}
+
+\LMHash{}%
+\Case{Top-level Functions and Static Methods}
+Consider the situation where $f$ denotes
+a top-level function or a static method.
+%
+In this situation, the program is modified such that $f$ is replaced by
+a reference $f'$ to an implicitly induced non-generic function
+whose signature is $F'$,
+whose dynamic type is $[t_1/T_1, \ldots, t_s/T_s]F'$,
+and whose semantics for each invocation is the same as
+invoking $f$ with \List{t}{1}{s} as the actual type argument list,
+where \List{t}{1}{s} is the actual value of \List{T}{1}{s}
+at the point during execution where $f'$ was evaluated.
+\commentary{Here is an example:}
+
+\begin{dartCode}
+List<T> foo<T>(T t) => [t];
+List<int> fooOfInt(int i) => [i];
+\\
+String bar(List<int> f(int)) => "\${f(42)}";
+\\
+\VOID{} main() \{
+  print(bar(foo));
+\}
+\end{dartCode}
+
+\commentary{%
+In this example,
+\code{foo} as an actual argument to \code{bar} will be modified
+as if the call had been \code{bar(fooOfInt)},
+except for equality, which is specified next.
+}
+
+\LMHash{}%
+Consider the situation where the program
+before generic function instantiation contains
+two occurrences of $f$ in the same scope or different scopes,
+but denoting the same function,
+respectively the situation where
+an execution of the program containing $f$ evaluates it twice.
+Let $o_1$ and $o_2$ denote the function objects obtained by
+evaluation of those two expressions,
+respectively the two evaluations of that expression.
+
+\LMHash{}%
+In the case where the actual values of the type arguments
+are the same for both evaluations,
+it is guaranteed that $o_1$ and $o_2$ are equal
+according to operator \lit{==}.
+However, it is unspecified whether
+\code{identical($o_1$, $o_2$)} evaluates to \TRUE{} or \FALSE{}.
+
+\rationale{%
+No notion of equality is appropriate
+when different type arguments are provided,
+even if the resulting function objects
+turn out to have exactly the same type at run time,
+because execution of two function objects that differ in these ways
+can have different side-effects and return different results
+when executed starting from exactly the same state.%
+}
+\commentary{%
+For instance, there could be a type parameter \code{X}
+that does not occur in the signature of the function,
+and the function could create and return a \code{List<X>}.%
+}
+
+\LMHash{}%
+\Case{Local Functions}
+Consider the situation where $f$ is an identifier denoting a local function.
+\commentary{For a local function, only an identifier can denote it.}
+%
+In this situation, the program is modified such that $f$ is replaced by
+a reference $f'$ to an implicitly induced non-generic function
+whose signature is $F'$,
+whose dynamic type is $[t_1/T_1, \ldots, t_s/T_s]F'$,
+and whose semantics for each invocation is the same as
+invoking $f$ with \List{t}{1}{s} as the actual type argument list,
+where \List{t}{1}{s} is the actual value of \List{T}{1}{s}
+at the point during execution where $f'$ was evaluated.
+
+\commentary{%
+No guarantees are provided regarding equality
+of non-generic functions obtained from a local function
+by generic function instantiation.%
+}
+
+\rationale{%
+Such a local function could have received exactly
+the same actual type arguments in the two cases,
+and still its body could contain references
+to declarations of types, variables, and other entities
+in the enclosing scopes.
+Those references could denote different entities
+when the two function objects were created.
+In that situation it is unreasonable
+to consider the two function objects to be the same function.%
+}
+\EndCase{}
+
+
 \subsection{Lookup}
 \LMLabel{lookup}
 
@@ -8337,12 +8776,12 @@
 A lookup may be part of the static analysis, and it may be performed
 at run time. It may succeed or fail.
 
-\commentary{
+\commentary{%
 We define several kinds of lookup with a very similar structure.
 We spell out each of them in spite of the redundancy,
 in order to avoid introducing meta-level abstraction mechanisms just for this purpose.
 The point is that we must indicate for each lookup which kind of member it is looking for,
-because, e.g., a `method lookup' and a `getter lookup' are used in different situations.
+because, e.g., a `method lookup' and a `getter lookup' are used in different situations.%
 }
 
 { % Scope for 'lookup' definition.
@@ -9237,6 +9676,259 @@
 \code{$c_1$ == $c_2$} is then true if and only if $o_1$ and $o_2$ is the same object.
 
 
+\subsubsection{Generic Method Instantiation}
+\LMLabel{genericMethodInstantiation}
+
+%% TODO(eernst): Like generic function instantiation, generic method instantiation
+%% relies on type inference. See the comment in \ref{genericFunctionInstantiation}
+%% for further details.
+
+\LMHash{}%
+Generic method instantiation is a mechanism that yields
+a non-generic function object,
+based on a property extraction which denotes an instance method closurization
+(\ref{ordinaryMemberClosurization}, \ref{superClosurization}).
+
+\commentary{%
+It is a mechanism which is very similar to instance method closurization,
+but it only occurs in situations where
+a compile-time error would otherwise occur.%
+}
+
+\rationale{%
+The essence of generic method instantiation
+is to allow for ``curried'' invocations,
+in the sense that a generic instance method can receive its actual
+type arguments separately during closurization
+(it must then receive \emph{all} type arguments, not just some of them),
+and that yields a non-generic function object.
+The type arguments are passed implicitly, based on type inference;
+a future version of Dart may allow for passing them explicitly.%
+}
+\commentary{Here is an example:}
+
+\begin{dartCode}
+\CLASS{} A \{
+  X fi<X \EXTENDS{} num>(X x) => x;
+\}
+\\
+\CLASS{} B \EXTENDS{} /*\,or\,\,\IMPLEMENTS\,*/ A \{
+  X fi<X \EXTENDS{} num>(X x, [List<X> xs]) => x;
+\}
+\\
+\VOID{} main() \{
+  A a = B();
+  int \FUNCTION{}(int) f = a.fi;
+\}
+\end{dartCode}
+
+\commentary{%
+\noindent
+The function object which is stored in \code{f} at the end of \code{main}
+has dynamic type \code{int\,\,\FUNCTION(int,\,[List<int>])},
+and it is obtained by implicitly
+``passing the actual type argument \code{int}''
+to the denoted generic instance method,
+thus obtaining a non-generic function object of the specified type.
+%
+Note that this function object accepts an optional positional argument,
+even though this is not part of
+the statically known type of the corresponding instance method,
+nor of the context type.
+}
+
+\rationale{%
+In other words, generic method instantiation yields a function
+whose signature matches the context type as far as possible,
+but with respect to its parameter list shape
+(that is, the number of positional parameters and their optionality,
+or the set of names of named parameters),
+it will be determined by the method signature of the actual instance method
+of the given receiver.
+Of course, the difference can only be such that the actual type is
+% This is about the dynamic type, so there is no exception for \COVARIANT.
+a subtype of the given context type,
+otherwise the declaration of that instance method
+would have been a compile-time error.%
+}
+
+\LMHash{}%
+Let $i$ be a property extraction expression of the form
+\code{$e$?.\id}, \code{$e$.\id}, or \code{\SUPER.\id}
+(\ref{propertyExtraction}, \ref{superGetterAccessAndMethodClosurization}),
+which is statically resolved to denote an instance method named \id,
+and let $G$ be the static type of $i$.
+Consider the situation where $G$ is a function type of the form
+\RawFunctionType{T_0}{X}{B}{s}{\metavar{parameters}}
+with $s > 0$
+(\commentary{that is, $G$ is a generic function type}),
+and the context type is a non-generic function type $F$.
+In this situation a compile-time error occurs
+(\ref{variables},
+\ref{functions},
+\ref{generativeConstructors},
+\ref{redirectingGenerativeConstructors},
+\ref{initializerLists},
+\ref{new},
+\ref{const},
+\ref{bindingActualsToFormals},
+\ref{assignment},
+\ref{localVariableDeclaration},
+\ref{switch},
+\ref{return},
+\ref{yieldEach}),
+except when generic function type instantiation
+(\ref{genericFunctionInstantiation})
+succeeds, that is:
+
+\LMHash{}%
+Type inference is applied to $G$ with context type $F$,
+and it succeeds, yielding the actual type argument list
+\List{T}{1}{s}.
+
+{ % Scope for \gmiName.
+
+\def\gmiName{\metavar{gmiName\ensuremath{_{\id}}}}
+
+% For any given method name \id, \gmiName is the "associated" name which
+% is used for the implicitly induced method that we use to get the function
+% object which is the result of a generic method instantiation. Let's call
+% that associated method the "generic instantiation method".
+%
+% The basic idea is that we consider all libraries included in the
+% compilation of a complete Dart program, and then we select a suffix,
+% say `_*`, which is globally unique (because no user-written identifier
+% can have that suffix, and the compiler doesn't use anything similar
+% for other purposes).
+%
+% When we have found such a "globally fresh suffix", it is easy to see
+% that we can use it to specify the implicitly induced methods in a way
+% that will do the right thing:
+%
+% Assume that a class `C` has a generic method `foo`, and it is subject
+% to generic method instantiation.
+%
+% We then generate a generic instantiation method for `foo` in in `C`, with the
+% name `foo_*`. If there is a subclass `D` of `C` which has an overriding
+% declaration of `foo` then we also generate a `foo_*` generic instantiation
+% method in `D`, and that one might return a closure with a different parameter
+% list shape, because that's the way `foo` is declared in `D`.
+%
+% We can then call `e.foo_*<...>()` where `e` has static type `C`,
+% at a location where the original source code had `e.foo` and the context
+% type was non-generic (so generic method instantiation kicked in).
+% This may invoke `foo_*` in `C`, or `D`, or some other class, whatever is the
+% dynamic type of the result of evaluating `e`.
+%
+% Altogether, this ensures that we obtain a function object whose parameter
+% list shape corresponds precisely to the parameter list shape of `foo` in
+% the dynamic type of the receiver, as it should. There will not be any
+% name clashes with user-written declarations, and overriding declarations
+% will actually override as they should, because they all use that same
+% "globally fresh suffix".
+%
+% The text below tries to communicate how this could work without being too
+% much like a particular implementation.
+
+\LMHash{}%
+Consider the situation where generic function type instantiation succeeded.
+Let \gmiName{} be a fresh name which is associated with \id{},
+which is private if and only if \id{} is private.
+\commentary{%
+An implementation could use, say, \code{foo_*} when \id{} is \code{foo},
+which is known to be fresh because user-written identifiers cannot contain `\code{*}'.%
+}
+The program is then modified as follows:
+
+\begin{itemize}
+\item When $i$ is \code{$e$?.\id}:
+  Replace $i$ by \code{$e$?.\gmiName<\List{T}{1}{s}>()}.
+\item When $i$ is \code{$e$.\id}:
+  Replace $i$ by \code{$e$.\gmiName<\List{T}{1}{s}>()}.
+\item When $i$ is \code{\SUPER.\id}:
+  Replace $i$ by \code{\SUPER.\gmiName<\List{T}{1}{s}>()}.
+\end{itemize}
+
+\LMHash{}%
+The inserted expressions have no compile-time error and can be executed,
+because the corresponding generic method is induced implicitly.
+We use the phrase
+\Index{generic instantiation method}
+to denote these implicitly induced methods,
+and designate the method that induced it as its
+\IndexCustom{target}{generic instantiation method!target}.
+
+\LMHash{}%
+Assume that a class $C$ declares a generic instance method named \id,
+with a method signature corresponding to a generic function type $G$,
+formal type parameters \TypeParametersStd{},
+and formal parameter declarations \metavar{parameters}.
+Let \metavar{arguments} denote the corresponding actual argument list,
+passing these parameters.
+\commentary{%
+For instance, \metavar{parameters} could be
+
+\noindent
+\code{$\PairList{T}{p}{1}{n},\ $\{$T_{n+1}\ p_{n+1} = d_1, \ldots,\ T_{n+k}\ p_{n+k} = d_k$\}}
+
+\noindent
+in which case \metavar{arguments} would be
+\code{\List{p}{1}{n},\ $p_{n+1}$:\ $p_{n+1}$,\ $p_{n+k}$:\ $p_{n+k}$}.%
+}
+
+\LMHash{}%
+Let $G'$ be the same function type as $G$,
+except that it omits the formal type parameter declarations.
+\commentary{%
+For instance, if $G$ is
+\FunctionTypeSimpleGeneric{\VOID}{$X$, $Y$ \EXTENDS\ num}{X x, List<Y> ys}
+then $G'$ is
+\FunctionTypeSimple{\VOID}{X x, List<Y> ys}.
+Note that $G'$ will typically contain free type variables.
+}
+
+\LMHash{}%
+An instance method with the name \gmiName{} is then implicitly induced,
+with the same behavior as the following declaration
+(except for equality of the returned function object,
+which is specified below):
+
+% Use `\THIS.\id..` because there could be a parameter named \id.
+\begin{normativeDartCode}
+$G'$ \gmiName<\TypeParametersStd{}>() \{
+\ \ \RETURN{} (\metavar{parameters}) => \THIS.\id<\List{X}{1}{s}>(\metavar{arguments});
+\}
+\end{normativeDartCode}
+
+\LMHash{}%
+Let $o$ be an instance of a class which contains
+an implicitly induced declaration of \gmiName{}
+as described above.
+%
+Consider the situation where the program evaluates
+two invocations of this method with the same receiver $o$,
+and with actual type arguments whose actual values are
+the same types \List{t}{1}{s} for both invocations,
+and assume that the invocations returned
+the instances $o_1$ respectively $o_2$.
+%
+It is then guaranteed that $o_1$ and $o_2$ are equal
+according to operator \lit{==}.
+It is unspecified whether
+\code{identical($o_1$, $o_2$)}
+evaluates to \TRUE{} or \FALSE{}.
+
+} % End of scope for \gmiName.
+
+\rationale{%
+No notion of equality is appropriate with different receivers,
+nor when different type arguments are provided,
+because execution of two function objects that differ in these ways
+can have different side-effects and return different results
+when executed starting from exactly the same state.%
+}
+
+
 \subsection{Assignment}
 \LMLabel{assignment}
 
@@ -9314,8 +10006,9 @@
 Otherwise, the assignment is equivalent to the assignment \code{\THIS{}.$v$ = $e$}.
 
 \LMHash{}%
-It is a dynamic type error if $o$ is not the null object (\ref{null})
-and the dynamic type of $o$ is not a subtype of the actual type
+% This error can occur due to implicit casts.
+It is a dynamic type error if the dynamic type of $o$
+is not a subtype of the actual type
 (\ref{actualTypeOfADeclaration})
 of $v$.
 \EndCase
@@ -9356,6 +10049,7 @@
 The expression $e_1$ is evaluated to an object $o_1$.
 Then, the expression $e_2$ is evaluated to an object $o_2$.
 Then, the setter \code{$v$=} is looked up (\ref{lookup}) in $o_1$ with respect to the current library.
+% This error can occur due to implicit casts and dynamic calls.
 It is a dynamic type error if the dynamic type of $o_2$
 is not a subtype of the actual parameter type of said setter
 (\ref{actualTypeOfADeclaration}).
@@ -9416,6 +10110,7 @@
 The value of the assignment expression is $o$.
 
 \LMHash{}%
+% This error can occur due to implicit casts and mixin+covariance.
 It is a dynamic type error if $o$ is not the null object (\ref{null})
 and the dynamic type of $o$ is
 not a subtype of the actual type of the formal parameter of \code{$v$=}
@@ -9583,7 +10278,7 @@
 \Case{\code{$C$?.$v$ ??= $e_2$}}
 A compound assignment of the form \code{$C$?.$v$ ??= $e_2$}
 where $C$ is a type literal
-that may or may not be be qualified by an import prefix
+that may or may not be qualified by an import prefix
 is equivalent to the expression \code{$C$.$v$ ??= $e$}.
 \EndCase
 
@@ -9693,7 +10388,8 @@
 
 \LMHash{}%
 First, $e_1$ is evaluated to an object $o_1$.
-It is a run-time error if the run-time type of $o_1$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o_1$ is not \code{bool}.
 If $r$ is \TRUE, then the value of $c$ is the result of evaluating the expression $e_2$.
 Otherwise the value of $c$ is the result of evaluating the expression $e_3$.
 
@@ -9756,16 +10452,20 @@
 
 \LMHash{}%
 Evaluation of a logical boolean expression $b$ of the form $e_1 || e_2$ causes the evaluation of $e_1$ to a value $o_1$.
-It is a run-time error if the run-time type of $o_1$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o_1$ is not \code{bool}.
 If $o_1$ is \TRUE, the result of evaluating $b$ is \TRUE, otherwise $e_2$ is evaluated to an object $o_2$.
-It is a run-time error if the run-time type of $o_2$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o_2$ is not \code{bool}.
 Otherwise the result of evaluating $b$ is $o_2$.
 
 \LMHash{}%
 Evaluation of a logical boolean expression $b$ of the form $e_1 \&\& e_2$ causes the evaluation of $e_1$ producing an object $o_1$.
-It is a run-time error if the run-time type of $o_1$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o_1$ is not \code{bool}.
 If $o_1$ is \FALSE, the result of evaluating $b$ is \FALSE, otherwise $e_2$ is evaluated to an object $o_2$.
-It is a run-time error if the run-time type of $o_2$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o_2$ is not \code{bool}.
 Otherwise the result of evaluating $b$ is $o_2$.
 
 \LMHash{}%
@@ -9842,7 +10542,7 @@
 \end{itemize}
 
 \commentary{
-As a result of the above definition, user defined \code{==} methods can assume that their argument is non-null, and avoid the standard boiler-plate prelude:
+As a result of the above definition, user defined \lit{==} methods can assume that their argument is non-null, and avoid the standard boiler-plate prelude:
 
 \code{if (identical(\NULL{}, arg)) return \FALSE{};}
 
@@ -10012,6 +10712,7 @@
 The static type of an expression $e_1 * e_2$ where $e_1$ has static type \code{int} is \code{int} if the static type of $e_2$ is \code{int}, and \code{double} if the static type of $e_2$ is \code{double}.
 The static type of an expression $e_1 \% e_2$ where $e_1$ has static type \code{int} is \code{int} if the static type of $e_2$ is \code{int}, and \code{double} if the static type of $e_2$ is \code{double}.
 
+
 \subsection{Unary Expressions}
 \LMLabel{unaryExpressions}
 
@@ -10110,22 +10811,24 @@
 
 %Otherwise, the value of $a$ is the value of $e$. If evaluation of $e$ raises an exception $x$, $a$ raises $x$.
 
-\commentary{
-It is a compile-time error if the function immediately enclosing $a$ is not declared asynchronous.
-However, this error is simply a syntax error, because in the context of a normal function, \AWAIT{} has no special meaning.
-% TODO(lrn): Update this, it's not actually correct,
-% the expression "await(expr)" is valid non-async syntax *and* a valid
-% async await expression.
+\commentary{%
+It is typically a compile-time error
+if the function immediately enclosing $a$ is not declared asynchronous.
+E.g., it can be a syntax error because \AWAIT{} has no special meaning
+in the context of a normal function.
+However, \code{\AWAIT($e$)} can also be a function invocation.%
 }
 
-\rationale{
+\rationale{%
 An await expression has no meaning in a synchronous function.
-If such a function were to suspend waiting for a future, it would no longer be synchronous.
+If such a function were to suspend waiting for a future,
+it would no longer be synchronous.%
 }
 
-\commentary{
-It is not a compile-time error if the type of $e$ is not a subtype of \code{Future}.
-Tools may choose to give a hint in such cases.
+\commentary{%
+It is not a compile-time error if the type of $e$ is not
+a subtype of \code{Future}.
+Tools may choose to give a hint in such cases.%
 }
 
 \LMHash{}%
@@ -10436,7 +11139,7 @@
 If no such declaration exists in the lexical scope, let $d$ be the declaration of the inherited member named \id{} if it exists.
 
 \begin{itemize}
-\item if $d$ is a prefix $p$, a compile-time error occurs unless the token immediately following $d$ is \code{'.'}.
+\item if $d$ is a prefix $p$, a compile-time error occurs unless the token immediately following $d$ is `\code{.}'.
 \item If $d$ is a class or type alias $T$, the value of $e$ is an object implementing the class \code{Type} which reifies $T$.
 \item If $d$ is a type parameter $T$, then the value of $e$ is the value of the actual type argument corresponding to $T$ that was passed to the generative constructor that created the current binding of \THIS{}.
 If, however, $e$ occurs inside a static member, a compile-time error occurs.
@@ -10511,9 +11214,8 @@
 
 \LMHash{}%
 The expression $e$ is evaluated to a value $v$.
-% TODO(eernst): https://github.com/dart-lang/sdk/issues/34521.
-Then, if $T$ is a malformed or deferred type (\ref{staticTypes}), a dynamic error occurs.
-Otherwise, if the dynamic type of $v$ is a subtype of $T$, the is-expression evaluates to \TRUE.
+If the dynamic type of $v$ is a subtype of $T$,
+the is-expression evaluates to \TRUE.
 Otherwise it evaluates to \FALSE.
 
 \commentary{
@@ -10580,9 +11282,8 @@
 
 \LMHash{}%
 The expression $e$ is evaluated to a value $v$.
-%% TODO(eernst): https://github.com/dart-lang/sdk/issues/34521
-Then, if $T$ is a malformed or deferred type (\ref{staticTypes}), a dynamic error occurs.
-It is a dynamic type error if $o$ is not the null object (\ref{null})
+% This error can occur, by design of `as`.
+It is a dynamic type error if $o$ is not the null object (\ref{null}),
 and the dynamic type of $o$ is not a subtype of $T$.
 Otherwise $e$ evaluates to $v$.
 
@@ -10696,22 +11397,24 @@
 
 \LMHash{}%
 An \Index{expression statement} consists of an expression that does not
-begin with a \syntax{`{'} character.
+begin with a \lit{\{} character.
 
 \begin{grammar}
 <expressionStatement> ::= <expression>? `;'
 \end{grammar}
 
 \LMHash{}%
-The expression of an expression statement is not allowed to begin with a \syntax{`\{'}.
+The expression of an expression statement is not allowed
+to begin with a \lit{\{}.
 \commentary{
 This means that if some source text could otherwise be parsed as an expression
-followed by a \syntax{`;'}, then this grammar production does not apply
-when the expression starts with a \syntax{`\{'}.
+followed by a \lit{;}, then this grammar production does not apply
+when the expression starts with a \lit{\{}.
 }
 \rationale{
 The restriction resolves an ambiguity while parsing where a
-\syntax{`\{'} can start either a block (\ref{blocks}) or a map literal (\ref{maps}).
+\lit{\{} can start either a block (\ref{blocks}) or
+a map literal (\ref{maps}).
 By disallowing the latter from starting an expression statement,
 the parser does not need to look further ahead
 before deciding that it is parsing a block statement.
@@ -10884,6 +11587,7 @@
 \LMHash{}%
 The expression $e$ is evaluated to an object $o$.
 Then, the variable $v$ is set to $o$.
+% This error can occur due to implicit casts.
 A dynamic type error occurs
 if the dynamic type of $o$ is not a subtype of the actual type
 (\ref{actualTypeOfADeclaration})
@@ -10999,7 +11703,8 @@
 
 \LMHash{}%
 First, the expression $b$ is evaluated to an object $o$.
-It is a run-time error if the run-time type of $o$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o$ is not \code{bool}.
 If $o$ is \TRUE{}, then the block statement $s_1$ is executed, otherwise the block statement $s_2$ is executed.
 
 \LMHash{}%
@@ -11061,7 +11766,8 @@
 Otherwise, let $v'$ be the variable $v''$ created in the previous execution of step \ref{allocateFreshVar}.
 \item
 The expression $[v'/v]c$ is evaluated to a value $o$.
-It is a run-time error if the run-time type of $o$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o$ is not \code{bool}.
 If $o$ is \FALSE{}, the for loop completes normally.
 Otherwise, execution continues at step \ref{beginIteration}.
 \item
@@ -11149,6 +11855,7 @@
 
 \LMHash{}%
 The expression $e$ is evaluated to an object $o$.
+% This error can occur due to implicit casts and null.
 It is a dynamic type error if $o$ is not an instance of a class that implements \code{Stream}.
 It is a compile-time error if $D$ is empty and \id{} is a final variable.
 
@@ -11234,7 +11941,8 @@
 
 \LMHash{}%
 The expression $e$ is evaluated to an object $o$.
-It is a run-time error if the run-time type of $o$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o$ is not \code{bool}.
 
 \LMHash{}%
 If $o$ is \FALSE{}, then execution of the while statement completes normally (\ref{statementCompletion}).
@@ -11271,7 +11979,8 @@
 
 \LMHash{}%
 Then, the expression $e$ is evaluated to an object $o$.
-It is a run-time error if the run-time type of $o$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o$ is not \code{bool}.
 If $o$ is \FALSE{}, execution of the do statement completes normally (\ref{statementCompletion}).
 If $o$ is \TRUE{}, then the do statement is re-executed.
 
@@ -11334,25 +12043,23 @@
 }
 
 \LMHash{}%
-It is a compile-time error if the class $C$ has an implementation of
-the operator \code{==} other than the one inherited from \code{Object},
-unless the expression evaluates to a string or an integer,
-the expression evaluates to an instance of the built-in
-class \code{Symbol} which was initially obtained by evaluation of a
-literal symbol or
-a constant invocation of a constructor of the \code{Symbol} class,
-or to an object implementing the built-in class \code{Type}
-which was originally created by evaluating a constant type literal
-(\ref{dynamicTypeSystem}).
+It is a compile-time error if the operator \lit{==} of class $C$
+is not primitive
+(\ref{theOperatorEqualsEquals}).
 
 \rationale{
-The prohibition on user defined equality allows us to implement the switch efficiently for user defined types.
-We could formulate matching in terms of identity instead with the same efficiency.
-However, if a type defines an equality operator, programmers would find it quite surprising that equal objects did not match.
+The prohibition on user defined equality allows us to
+implement the switch efficiently for user defined types.
+We could formulate matching in terms of identity instead,
+with the same efficiency.
+However, if a type defines an equality operator,
+programmers would presumably find it quite surprising
+if equal objects did not match.
 }
 
 \commentary{
-The \SWITCH{} statement should only be used in very limited situations (e.g., interpreters or scanners).
+The \SWITCH{} statement should only be used in
+very limited situations (e.g., interpreters or scanners).
 }
 
 \LMHash{}%
@@ -11381,7 +12088,9 @@
 
 \LMHash{}%
 The statement \code{\VAR{} \id{} = $e$;} is evaluated, where \id{} is a fresh variable.
-It is a run-time error if the value of $e$ is
+% This error can occur due to implicit casts and standard subsumption.
+%% TODO(eernst): But why couldn't $e$ be an instance of a subtype?!
+It is a dynamic error if the value of $e$ is
 not an instance of the same class as the constants $e_1, \ldots, e_n$.
 
 \commentary{
@@ -11408,7 +12117,8 @@
 
 \LMHash{}%
 The expression \code{$e_k$ == \id} is evaluated to an object $o$.
-It is a run-time error if the run-time type of $o$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o$ is not \code{bool}.
 If $o$ is \FALSE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is matched against \id{} if $k < n$, and if $k = n$, then the \DEFAULT{} clause's statements are executed (\ref{case-execute}).
 If $o$ is \TRUE{}, let $h$ be the smallest number such that $h \ge k$ and $s_h$ is non-empty.
 If no such $h$ exists, let $h = n + 1$.
@@ -11429,7 +12139,8 @@
 
 \LMHash{}%
 The expression \code{$e_k$ == \id} is evaluated to an object $o$.
-It is a run-time error if the run-time type of $o$ is not \code{bool}.
+% This error can occur due to implicit casts and null.
+It is a dynamic error if the run-time type of $o$ is not \code{bool}.
 If $o$ is \FALSE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is matched against \id{} if $k < n$.
 If $o$ is \TRUE{}, let $h$ be the smallest integer such that $h \ge k$ and $s_h$ is non-empty.
 If such a $h$ exists, the case statements $s_h$ are executed (\ref{case-execute}).
@@ -11635,8 +12346,7 @@
 Otherwise the \TRY{} statement completes in the same way as the execution of $b$.
 
 \LMHash{}%
-If $T_1$ is a malformed or deferred type (\ref{staticTypes}), then performing a match causes a run-time error.
-It is a compile-time error if $T_i$, $1 \le i \le n$ is a deferred or malformed type.
+It is a compile-time error if $T_i$, $1 \le i \le n$ is a deferred type.
 
 
 \subsubsection{\ON{}-\CATCH{} clauses}
@@ -11871,8 +12581,10 @@
 \begin{itemize}
 \item
   If the body of $f$ is marked \ASYNC{} (\ref{functions})
+  % This error can occur due to implicit casts.
   it is a dynamic type error if \code{Future<$U$>} is not a subtype of $T$.
 \item
+  % This error can occur due to implicit casts.
   Otherwise, it is a dynamic type error if $U$ is not a subtype of $T$.
 \end{itemize}
 
@@ -12058,16 +12770,30 @@
 \LMHash{}%
 If the immediately enclosing function $m$ is marked \code{\SYNC*} (\ref{functions}), then:
 \begin{enumerate}
-\item It is a dynamic type error if the class of $o$ does not implement \code{Iterable}.
-Otherwise
-\item The method \code{iterator} is invoked upon $o$ returning an object $i$.
-\item \label{moveNext} The \code{moveNext} method of $i$ is invoked on it with no arguments.
-If \code{moveNext} returns \FALSE{} execution of $s$ is complete.
-Otherwise
-\item The getter \code{current} is invoked on $i$.
-If the invocation throws (\ref{evaluation}), execution of $s$ throws the same exception object and stack trace (\ref{statementCompletion}).
-Otherwise, the result $x$ of the getter invocation is added to the iterable associated with $m$.
-Execution of the function $m$ immediately enclosing $s$ is suspended until the nullary method \code{moveNext()} is invoked upon the iterator used to initiate the current invocation of $m$, at which point execution of $s$ continues at \ref{moveNext}.
+\item
+  % This error can occur due to implicit casts.
+  It is a dynamic type error
+  if the class of $o$ does not implement \code{Iterable}.
+  Otherwise
+\item
+  The method \code{iterator} is invoked upon $o$ returning an object $i$.
+\item
+  \label{moveNext} The \code{moveNext} method of $i$ is invoked on it
+  with no arguments.
+  If \code{moveNext} returns \FALSE{} execution of $s$ is complete.
+  Otherwise
+\item
+  The getter \code{current} is invoked on $i$.
+  If the invocation throws
+  (\ref{evaluation}),
+  execution of $s$ throws the same exception object and stack trace
+  (\ref{statementCompletion}).
+  Otherwise, the result $x$ of the getter invocation is added to
+  the iterable associated with $m$.
+  Execution of the function $m$ immediately enclosing $s$ is suspended
+  until the nullary method \code{moveNext()} is invoked
+  upon the iterator used to initiate the current invocation of $m$,
+  at which point execution of $s$ continues at \ref{moveNext}.
 \item
 The current call to \code{moveNext()} returns \TRUE.
 \end{enumerate}
@@ -12075,32 +12801,50 @@
 \LMHash{}%
 If $m$ is marked \code{\ASYNC*} (\ref{functions}), then:
 \begin{itemize}
-\item It is a dynamic type error if the class of $o$ does not implement \code{Stream}.
+\item
+  % This error can occur due to implicit casts.
+  It is a dynamic type error if the class of $o$
+  does not implement \code{Stream}.
 Otherwise
-\item The nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused.
-\item The $o$ stream is listened to, creating a subscription $s$, and for each event $x$, or error $e$ with stack trace $t$, of $s$:
+\item
+  The nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}),
+  if any, is paused.
+\item
+  The $o$ stream is listened to, creating a subscription $s$,
+  and for each event $x$, or error $e$ with stack trace $t$, of $s$:
 \begin{itemize}
 \item
-If the stream $u$ associated with $m$ has been paused, then execution of $m$ is suspended until $u$ is resumed or canceled.
+  If the stream $u$ associated with $m$ has been paused,
+  then execution of $m$ is suspended until $u$ is resumed or canceled.
 \item
-If the stream $u$ associated with $m$ has been canceled,
-then $s$ is canceled by evaluating \code{\AWAIT{} v.cancel()} where $v$ is a fresh variable referencing the stream subscription $s$.
-Then, if the cancel completed normally, the stream execution of $s$ returns without a value (\ref{statementCompletion}).
+  If the stream $u$ associated with $m$ has been canceled,
+  then $s$ is canceled by evaluating \code{\AWAIT{} v.cancel()}
+  where $v$ is a fresh variable referencing the stream subscription $s$.
+  Then, if the cancel completed normally,
+  the stream execution of $s$ returns without a value
+  (\ref{statementCompletion}).
 \item
-Otherwise, $x$, or $e$ with $t$, are added to the stream associated with $m$ in the order they appear in $o$.
-The function $m$ may suspend.
+  Otherwise, $x$, or $e$ with $t$, are added to
+  the stream associated with $m$ in the order they appear in $o$.
+  The function $m$ may suspend.
 \end{itemize}
-\item If the stream $o$ is done, execution of $s$ completes normally.
+\item
+  If the stream $o$ is done, execution of $s$ completes normally.
 \end{itemize}
 
 \LMHash{}%
-It is a compile-time error if a yield-each statement appears in a function that is not a generator function.
+It is a compile-time error if a yield-each statement appears
+in a function that is not a generator function.
 
 \LMHash{}%
-Let $T$ be the static type of $e$ and let $f$ be the immediately enclosing function.
-It is a compile-time error if $T$ may not be assigned to the declared return type of $f$.
-If $f$ is synchronous it is a compile-time error if $T$ may not be assigned to \code{Iterable}.
-If $f$ is asynchronous it is a compile-time error if $T$ may not be assigned to \code{Stream}.
+Let $T$ be the static type of $e$ and let $f$ be
+the immediately enclosing function.
+It is a compile-time error if $T$ may not be assigned to
+the declared return type of $f$.
+If $f$ is synchronous it is a compile-time error
+if $T$ may not be assigned to \code{Iterable}.
+If $f$ is asynchronous it is a compile-time error
+if $T$ may not be assigned to \code{Stream}.
 
 
 \subsection{Assert}
@@ -12138,6 +12882,7 @@
 
 \LMHash{}%
 The expression $c$ is evaluated to an object $r$.
+% This error can occur due to implicit casts and null.
 It is a dynamic type error if $r$ is not of type \code{bool}.
 \commentary{
 Hence it is a compile-time error if that situation arises during evaluation of an assertion in a \CONST{} constructor invocation.
@@ -12249,8 +12994,9 @@
 Script tags are intended for use with scripts (\ref{scripts}).
 A script tag can be used to identify the interpreter of the script to whatever computing environment the script is embedded in.
 The script tag must appear before any whitespace or comments.
-A script tag begins with \syntax{`#!'} and ends at the end of the line.
-Any characters that follow \syntax{`#!'} in the script tag are ignored by the Dart implementation.
+A script tag begins with \lit{\#!} and ends at the end of the line.
+Any characters that follow \lit{\#!} in the script tag are ignored by
+the Dart implementation.
 
 \LMHash{}%
 Libraries are units of privacy.
@@ -12316,7 +13062,8 @@
 It is a compile-time error if a prefix used in a deferred import is used in another import clause.
 
 \LMHash{}%
-An import directive $I$ may optionally include a namespace combinator clauses used to restrict the set of names imported by $I$.
+An import directive $I$ may optionally include namespace combinator clauses
+used to restrict the set of names imported by $I$.
 Currently, two namespace combinators are supported: \HIDE{} and \SHOW{}.
 
 \LMHash{}%
@@ -12336,14 +13083,26 @@
 When called, the method causes an immediate import $I'$ to be executed at some future time, where $I'$ is derived from $I$ by eliding the word \DEFERRED{} and adding a \HIDE{} \code{loadLibrary} combinator clause.
 When $I'$ executes without error, $f$ completes successfully.
 If $I'$ executes without error, we say that the call to \code{loadLibrary} has succeeded, otherwise we say the call has failed.
-\item For every top level function $f$ named \id{} in the imported library $B$, a corresponding method named \id{} with the same signature as $f$.
-Calling the method results in a run-time error.
-\item For every top level getter $g$ named \id{} in $B$, a corresponding getter named \id{} with the same signature as $g$.
-Calling the method results in a run-time error.
-\item For every top level setter $s$ named \id{} in $B$, a corresponding setter named \id{} with the same signature as $s$.
-Calling the method results in a run-time error.
-\item For every type $T$ named \id{} in $B$, a corresponding getter named \id{} with return type \code{Type}.
-Calling the method results in a run-time error.
+\item
+  For every top level function $f$ named \id{} in the imported library $B$,
+  a corresponding method named \id{} with the same signature as $f$.
+  % This error can occur because being-loaded is a dynamic property.
+  Calling the method results in a dynamic error.
+\item
+  For every top level getter $g$ named \id{} in $B$,
+  a corresponding getter named \id{} with the same signature as $g$.
+  % This error can occur because being-loaded is a dynamic property.
+  Calling the method results in a dynamic error.
+\item
+  For every top level setter $s$ named \id{} in $B$,
+  a corresponding setter named \id{} with the same signature as $s$.
+  % This error can occur because being-loaded is a dynamic property.
+  Calling the method results in a dynamic error.
+\item
+  For every type $T$ named \id{} in $B$,
+  a corresponding getter named \id{} with return type \code{Type}.
+  % This error can occur because being-loaded is a dynamic property.
+  Calling the method results in a dynamic error.
 \end{itemize}
 
 \rationale{
@@ -12418,7 +13177,10 @@
 \end{itemize}
 
 \LMHash{}%
-Next, if $I$ includes a prefix clause of the form \AS{} $p$, let $NS = NS_n \cup \{p: prefixObject(NS_n)\}$ where $prefixObject(NS_n)$ is a \Index{prefix object} for the namespace $NS_n$, which is an object that has the following members:
+Next, if $I$ includes a prefix clause of the form \AS{} $p$,
+let $NS = \{p: prefixObject(NS_n)\}$ where $prefixObject(NS_n)$ is
+a \Index{prefix object} for the namespace $NS_n$,
+which is an object that has the following members:
 
 \begin{itemize}
 \item For every top level function $f$ named \id{} in $NS_n$, a corresponding method with the same name and signature as $f$ that forwards (\ref{functionDeclarations}) to $f$.
@@ -12686,7 +13448,7 @@
 Then, the top-level function defined by \code{main}
 in the exported namespace of $S$ is invoked (\ref{functionInvocation})
 as follows:
-If \code{main} can be be called with with two positional arguments,
+If \code{main} can be called with with two positional arguments,
 it is invoked with the following two actual arguments:
 \begin{enumerate}
 \item An object whose run-time type implements \code{List<String>}.
@@ -12752,7 +13514,7 @@
 \item{} Let $u$ be \metavar{uri}.
 \item{} For each of the following configuration URIs of the form \code{\IF{} ($\metavar{test}_i$) $\metavar{uri}_i$}, in source order, do the following.
 \begin{itemize}
-  \item{} If $\metavar{test}_i$ is \code{\metavar{ids}} with no \code{==} clause, it is
+  \item{} If $\metavar{test}_i$ is \code{\metavar{ids}} with no \lit{==} clause, it is
   equivalent to \code{\metavar{ids} == "true"}.
   \item{} If $\metavar{test}_i$ is \code{\metavar{ids} == \metavar{string}},
   then create a string, \metavar{key}, from \metavar{ids}
@@ -12923,19 +13685,20 @@
 \item
   $T$ has the form \id{} or the form \code{\metavar{prefix}.\id},
   and in the enclosing lexical scope,
-  the name \id{} (respectively \code{\metavar{prefix}.\id}) does not denote a type.
-
+  the name \id{} (respectively \code{\metavar{prefix}.\id})
+  does not denote a type.
 \item
   $T$ denotes a type variable in the enclosing lexical scope,
   but occurs in the signature or body of a static member.
-
-\item $T$ is a parameterized type of the form \code{$G$<$S_1, \ldots,\ S_n$>},
+\item
+  $T$ is a parameterized type of the form \code{$G$<$S_1, \ldots,\ S_n$>},
   and $G$ is malformed,
   or $G$ is not a generic type,
-  or $G$ is a generic type, but it declares $n'$ type parameters and $n' \not= n$,
+  or $G$ is a generic type,
+  but it declares $n'$ type parameters and $n' \not= n$,
   or $S_j$ is malformed for some $j \in 1 .. n$.
-
-\item $T$ is a function type of the form
+\item
+  $T$ is a function type of the form
 
   \code{$T_0$ \FUNCTION{}<$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$>}
 
@@ -12952,24 +13715,20 @@
   where each $x_j$ which is not a named parameter may be omitted,
   and $T_j$ is malformed for some $j \in 0 .. n$,
   or $B_j$ is malformed for some $j \in 1 .. m$.
-
 \item
   $T$ denotes declarations that were imported from multiple imports clauses.
 \end{itemize}
 
 \LMHash{}%
-Any use of a malformed type gives rise to a compile-time error.
-A malformed type is then interpreted as \DYNAMIC{} by the static type checker unless explicitly specified otherwise.
-
-\rationale{
-This ensures that the developer is spared a series of cascading errors as the malformed type interacts with other types.
-}
+Any occurrence of a malformed type in a library is a compile-time error.
 
 \LMHash{}%
 A type $T$ is \IndexCustom{deferred}{type!deferred}
 if{}f it is of the form $p.T$ where $p$ is a deferred prefix.
-It is a compile-time error to use a deferred type in a type annotation, type test, type cast or as a type parameter.
-However, all other compile-time errors must be issued under the assumption that all deferred libraries have successfully been loaded.
+It is a compile-time error to use a deferred type
+in a type annotation, type test, type cast or as a type parameter.
+However, all other compile-time errors must be issued
+under the assumption that all deferred libraries have successfully been loaded.
 
 % Now, when passed to a generic, p.T also has to be treated as dynamic - otherwise we have to fail immediately. Where do we say that? And how does this fit with idea that as a type object it fails? Should we say that the accessor on p returns dynamic instead of failing? Do we distinguish its use in a constructor vs its use in an annotation? It's not that we evaluate type objects in constructor args - these cannot represent parameterized types.
 
@@ -13046,9 +13805,9 @@
 
 \LMHash{}%
 When types are reified as instances of the built-in class \code{Type},
-those objects override the \code{==} operator
+those objects override the \lit{==} operator
 inherited from the \code{Object} class, so that
-two \code{Type} objects are equal according to operator \syntax{`=='}
+two \code{Type} objects are equal according to operator \lit{==}
 if{}f the corresponding types are subtypes of each other.
 
 \commentary{
@@ -13090,6 +13849,7 @@
 A constant type literal is a constant expression (\ref{constants}).
 }
 
+
 \subsection{Type Aliases}
 \LMLabel{typedef}
 
@@ -13252,7 +14012,10 @@
 \LMHash{}%
 %% TODO(eernst): Introduce these specialized intersection types
 %% in a suitable location where type promotion is specified.
-Types of the form $X \& S$ arise during static analysis due to type promotion
+Types of the form
+\IndexCustom{$X \& S$}{type!of the form $X \& S$}%
+\IndexExtraEntry{\&@$X \& S$}
+arise during static analysis due to type promotion
 (\ref{typePromotion}).
 They never occur during execution,
 they are never a type argument of another type,
@@ -13996,7 +14759,7 @@
 
 \commentary{
 This \code{Type} object must compare equal to the corresponding \code{Type}
-objects for \code{Object} and \VOID{} according to operator `\code{==}'
+objects for \code{Object} and \VOID{} according to operator \lit{==}
 (\ref{dynamicTypeSystem}).
 }
 
@@ -14125,24 +14888,31 @@
 
 \LMHash{}%
 The built-in type declaration \code{FutureOr},
-which is declared in the library \code{dart:async},
+which is exported by the library \code{dart:async},
 defines a generic type with one type parameter (\ref{generics}).
+The type \code{FutureOr<$T$>} is a non-class type
+which is regular-bounded for all $T$.
 
-\LMHash{}%
-The \code{FutureOr<$T$>} type is a non-class type with the following
-type relations:
+\commentary{%
+The subtype relations involving \code{FutureOr} are specified elsewhere
+(\ref{subtypeRules}).
+Note, however, that they entail certain useful properties:
 \begin{itemize}
-    \item{} $T$ <: \code{FutureOr<$T$>}.
-    \item{} \code{Future<$T$>} <: \code{FutureOr<$T$>}.
-    \item{} If $T$ <: $S$ and \code{Future<$T$>} <: $S$
-        then \code{FutureOr<$T$>} <: $S$.
-        \commentary{In particular, \code{FutureOr<$T$>} <: \code{Object}.}
+\item[$\bullet$]
+  $T <: \code{FutureOr<$T$>}$.
+\item[$\bullet$]
+  $\code{Future<$T$>} <: \code{FutureOr<$T$>}$.
+\item[$\bullet$]
+  If $T <: S$ and $\code{Future<$T$>} <: S$, then $\code{FutureOr<$T$>} <: S$.
 \end{itemize}.
 
-\commentary{
-The last point guarantees that generic type \code{FutureOr} is
-\emph{covariant} in its type parameter, just like class types.
-That is, if $S$ <: $T$ then \code{FutureOr<$S$>} <: \code{FutureOr<$T$>}.
+That is, \code{FutureOr} is in a sense
+the union of $T$ and the corresponding future type.
+The last point guarantees that
+\code{FutureOr<$T$>} <: \code{Object},
+and also that \code{FutureOr} is covariant in its type parameter,
+just like class types:
+if $S$ <: $T$ then \code{FutureOr<$S$>} <: \code{FutureOr<$T$>}.%
 }
 
 \LMHash{}%
@@ -14153,42 +14923,45 @@
 denotes a \code{Type} object representing the type \code{FutureOr<dynamic>}.
 
 \rationale{
-The \code{FutureOr<\metavar{type}>} type represents a case where a value can be
-either an instance of the type \metavar{type}
-or the type \code{Future<\metavar{type}>}.
+The \code{FutureOr<$T$>} type represents a case where a value can be
+either an instance of the type $T$
+or the type \code{Future<$T$>}.
 Such cases occur naturally in asynchronous code.
-Using \code{FutureOr} instead of \DYNAMIC{} allows some tools
-to provide a more precise type analysis.
+The available alternative would be to use a top type (e.g., \DYNAMIC{}),
+but \code{FutureOr} allows some tools to provide a more precise type analysis.
 }
 
 \LMHash{}%
 The type \code{FutureOr<$T$>} has an interface that is identical to that
 of \code{Object}.
-
-\commentary{
-The only members that can be invoked on a value with static type
-\code{FutureOr<$T$>} are members that are also on \code{Object}.
+\commentary{%
+That is, only members that \code{Object} has can be invoked
+on a value with static type \code{FutureOr<$T$>}.%
 }
 
 \rationale{
 We only want to allow invocations of members that are inherited from
 a common supertype of both $T$ and \code{Future<$T$>}.
-In most cases the only common supertype is \code{Object}. The exceptions, like
-\code{FutureOr<Future<Object\gtgt} which has \code{Future<Object>} as common
-supertype, are few and not practically useful, so for now we choose to
-only allow invocations of members inherited from \code{Object}.
+In most cases the only common supertype is \code{Object}.
+The exceptions, like \code{FutureOr<Future<Object\gtgt}
+which has \code{Future<Object>} as common supertype,
+are few and not practically useful,
+so for now we choose to only allow invocations of
+members inherited from \code{Object}.
 }
 
 \LMHash{}%
 We define the auxiliary function
-\IndexCustom{\basetype{T}}{basetype(t)@\emph{basetype}$(T)$}
+\IndexCustom{\futureOrBase{T}}{futureOrBase(t)@\emph{futureOrBase}$(T)$}
 as follows:
 
 \begin{itemize}
-\item If $T$ is \code{FutureOr<$S$>} for some $S$ then $\basetype{T} = \basetype{S}$.
-\item Otherwise $\basetype{T} = T$.
+\item If $T$ is \code{FutureOr<$S$>} for some $S$
+  then $\futureOrBase{T} = \futureOrBase{S}$.
+\item Otherwise $\futureOrBase{T} = T$.
 \end{itemize}
 
+
 \subsection{Type Void}
 \LMLabel{typeVoid}
 
@@ -14225,7 +14998,7 @@
 the value of an expression of type \VOID.
 %
 Consequently, any instance of type \code{Type} which reifies the type \VOID{}
-must compare equal (according to the \code{==} operator \ref{equality})
+must compare equal (according to the \lit{==} operator \ref{equality})
 to any instance of \code{Type} which reifies the type \code{Object}
 (\ref{dynamicTypeSystem}).
 It is not guaranteed that \code{identical(\VOID, Object)} evaluates to true.
@@ -14381,7 +15154,8 @@
 because it has type \VOID.%
 }
 
-\paragraph{Void Soundness}
+
+\subsubsection{Void Soundness}
 \LMLabel{voidSoundness}
 
 \LMHash{}%
diff --git a/docs/language/informal/generic-function-instantiation.md b/docs/language/informal/generic-function-instantiation.md
index 50098c2..80e9241 100644
--- a/docs/language/informal/generic-function-instantiation.md
+++ b/docs/language/informal/generic-function-instantiation.md
@@ -1,10 +1,11 @@
 # Generic Function Instantiation
 
-Author: eernst@.
+**Author**: eernst@.
 
-Version: 0.3 (2018-04-05)
+**Version**: 0.3 (2018-04-05)
 
-Status: Under implementation.
+**Status**: This document is now background material.
+For normative text, please consult the language specification.
 
 **This document** is a Dart 2 feature specification of _generic function
 instantiation_, which is the feature that implicitly coerces a reference to
diff --git a/docs/language/informal/subtyping.md b/docs/language/informal/subtyping.md
new file mode 100644
index 0000000..dedd41a
--- /dev/null
+++ b/docs/language/informal/subtyping.md
@@ -0,0 +1,9 @@
+# Dart 2.0 Static and Runtime Subtyping
+
+leafp@google.com
+
+**Status**: This document has been integrated into the language specification.
+Also, an updated version taking non-null types into account exists
+[here](https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md).
+
+**Contents of this document**: Deleted.
diff --git a/docs/process/breaking-changes.md b/docs/process/breaking-changes.md
new file mode 100644
index 0000000..adf71a2
--- /dev/null
+++ b/docs/process/breaking-changes.md
@@ -0,0 +1,155 @@
+# Dart SDK breaking change process
+
+The present document describes the Dart SDK philosophy for compatibility, and
+process for breaking changes.
+
+## Dart compatibility and philosophy
+
+Generally the Dart team strives to not make breaking changes, and to preserve
+compatibility of all Dart programs across stable Dart SDK releases. However, on
+occasion, we believe that breaking changes are needed, or justified:
+
+* Security: To resolve a security issue in the specification or implementation.
+
+* Unspecified behavior: Programs that depend on unspecified behavior may break
+  as such behavior is specified and implemented.
+
+* Implementation bugs: If the implementation deviates unintentionally from the
+  specification, programs may break as we rectify the implementation.
+
+* Evolution: If we deem that there is a very large benefit to changing current
+  behavior, we may choose to do so after careful consideration of the associated
+  impact of the change.
+
+## Scope of compatibility
+
+It is not practical to offer compatability to programs that do not follow
+best practices. Thus, the breaking change process assumes that programs
+abide by the following basic conditions:
+
+* Must contain no static analysis **errors**.
+
+* Must not rely on a certain runtime **error** being thrown (in other words, 
+  a new SDK might throw fewer errors than an old SDK).
+
+* Must access libraries via the public API (for example, must not reach into
+  the internals of a package located in the `/src/` directory).
+
+* Must not rely on an [experiment flag](flags.md).
+
+* Must not circumvent clear restrictions documented in the public API
+  documentation (for example, must not mixin a class clearly documented as
+  not intended to be used as a mixin).
+
+Compatibility is only considered between stable releases (i.e. releases from the
+[Dart stable
+channel](https://www.dartlang.org/tools/sdk/archive#stable-channel)).
+
+## Breaking change notification
+
+Anyone wishing to make a breaking change to Dart is expected to perform the
+following steps.  It is expected that all of these steps are followed prior
+to a change being released in a dev channel release.
+
+### Step 1: Announcement
+
+* Create an issue in the Dart SDK issue tracker labelled
+  `breaking-change-request` containing the following:
+
+  * The intended change in behavior.
+
+  * The justification/rationale for making the change.
+
+  * The expected impact of this change.
+
+  * Clear steps for mitigating the change.
+
+[TODO: Link to an issue template for this]
+
+* Email `announce@dartlang.org, flutter-announce@googlegroups.com`,:
+
+  * Subject: 'Breaking change [bug ID]: [short summary]'
+
+  * Very short summary of the intended change
+
+  * Link to the above mentioned issue
+
+  * A request that developers may leave comments in the linked issue, if this
+    breaking change poses a severe problem.
+
+### Step 2: Approval
+
+If there is a general agreement that the benefit of the change outweighs the
+cost of the change, a set of Dart SDK approvers will approve the change.
+Adequate time must be allowed after step 1, at a minimum 24 hours during the
+work week for smaller impact changes, and proportionally longer for higher
+impact changes.
+### Step 3: Execution
+
+If approved, the change may be made.
+
+After the breaking change had been made, the person who made the change must:
+
+* Resolve the breaking change issue and make a note that the change has landed
+
+* Make a note in the [Dart SDK changelog](`changelog.md`) detailing the change.
+  This must be prefixed `** Breaking change:`.
+
+* Reply to the original announcement email, and make a note that the change is
+  being implemented.
+
+If not approved, or if the requestor decides to not pursue the change, the
+requestor must:
+
+* Reply to the original announcement email, and make a note that the change is
+  has been rejected, with a quick summary of the rationale for that.
+## Unexpected breaking changes & roll-back requests
+
+If a developer notices a breaking change has been made in the dev or stable
+channels, and this change impacts a program that abides to the above defined
+scope of compatibility, and for which either:
+
+  * No breaking change was announced, or
+
+  * The impact of the change was significantly larger than described in the
+    breaking change announcement
+
+, then they may file a 'request for roll-back' using the following steps:
+
+* Create an issue in the Dart SDK issue tracker labelled
+  `roll-back-request` containing the following:
+
+  * If applicable, a link to the associated breaking change request issue
+
+  * A clear description of the actual impact, and if applicable a description of
+    how this differs from the expected impact.
+
+  * A link to the program that was affected, or another program that illustrated
+    the same effect.
+
+[TODO: Link to an issue template for this]
+
+Upon receiving such an issue the Dart SDK team will either:
+
+  * Roll-back the change, or
+
+  * Make a quick corrective action to correct the change, or
+
+  * Detail how the change in their opinion does not warrant a roll-back.
+
+If a breaking change is rolled-back, in addition:
+
+  * The breaking change request issue should be reopened
+
+### Roll-backs following unexpected changes
+
+If a roll-back occurs after what should have been a breaking change, the
+originator of the change is expected to follow the breaking change process to
+move forward.
+
+If a roll-back occurs after a breaking change, but where the impact was larger
+than anticipated, then the impacted party is expected to make a best effort to
+quickly rectify their program to either not be affected by the breaking change,
+or in some other way offer the originator a clear timeline for when the breaking
+change can be landed.
+
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
new file mode 100644
index 0000000..dc8817d
--- /dev/null
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This file has been automatically generated. Please do not edit it manually.
+// To regenerate the file, use the script
+// "pkg/analysis_server/tool/lsp_spec/generate_all.dart".
+
+// ignore_for_file: deprecated_member_use
+// ignore_for_file: deprecated_member_use_from_same_package
+// ignore_for_file: unnecessary_brace_in_string_interps
+// ignore_for_file: unused_import
+
+import 'dart:core' hide deprecated;
+import 'dart:core' as core show deprecated;
+import 'dart:convert' show JsonEncoder;
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/protocol/protocol_internal.dart'
+    show listEqual, mapEqual;
+import 'package:analyzer/src/generated/utilities_general.dart';
+
+const jsonEncoder = const JsonEncoder.withIndent('    ');
+
+class DartDiagnosticServer implements ToJsonable {
+  DartDiagnosticServer(this.port) {
+    if (port == null) {
+      throw 'port is required but was not provided';
+    }
+  }
+  static DartDiagnosticServer fromJson(Map<String, dynamic> json) {
+    final port = json['port'];
+    return new DartDiagnosticServer(port);
+  }
+
+  final num port;
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> __result = {};
+    __result['port'] = port ?? (throw 'port is required but was not set');
+    return __result;
+  }
+
+  static bool canParse(Object obj) {
+    return obj is Map<String, dynamic> &&
+        obj.containsKey('port') &&
+        obj['port'] is num;
+  }
+
+  @override
+  bool operator ==(other) {
+    if (other is DartDiagnosticServer) {
+      return port == other.port && true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, port.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+
+  @override
+  String toString() => jsonEncoder.convert(toJson());
+}
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
index 8e0f2a2..e0484bf 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
@@ -7,7 +7,9 @@
 // "pkg/analysis_server/tool/lsp_spec/generate_all.dart".
 
 // ignore_for_file: deprecated_member_use
+// ignore_for_file: deprecated_member_use_from_same_package
 // ignore_for_file: unnecessary_brace_in_string_interps
+// ignore_for_file: unused_import
 
 import 'dart:core' hide deprecated;
 import 'dart:core' as core show deprecated;
@@ -4980,10 +4982,15 @@
   /// range at the mouse position.
   final Range originSelectionRange;
 
-  /// The full target range of this link.
+  /// The full target range of this link. If the target for example is a symbol
+  /// then target range is the range enclosing this symbol not including
+  /// leading/trailing whitespace but everything else like comments. This
+  /// information is typically used to highlight the range in the editor.
   final Range targetRange;
 
-  /// The span of this link.
+  /// The range that should be selected and revealed when this link is being
+  /// followed, e.g the name of a function. Must be contained by the the
+  /// `targetRange`. See also `DocumentSymbol#range`
   final Range targetSelectionRange;
 
   /// The target resource identifier of this link.
@@ -4998,9 +5005,8 @@
         targetUri ?? (throw 'targetUri is required but was not set');
     __result['targetRange'] =
         targetRange ?? (throw 'targetRange is required but was not set');
-    if (targetSelectionRange != null) {
-      __result['targetSelectionRange'] = targetSelectionRange;
-    }
+    __result['targetSelectionRange'] = targetSelectionRange ??
+        (throw 'targetSelectionRange is required but was not set');
     return __result;
   }
 
@@ -5009,7 +5015,9 @@
         obj.containsKey('targetUri') &&
         obj['targetUri'] is String &&
         obj.containsKey('targetRange') &&
-        Range.canParse(obj['targetRange']);
+        Range.canParse(obj['targetRange']) &&
+        obj.containsKey('targetSelectionRange') &&
+        Range.canParse(obj['targetSelectionRange']);
   }
 
   @override
@@ -5353,234 +5361,182 @@
 
 /// Valid LSP methods known at the time of code generation from the spec.
 class Method {
-  const Method._(this._value);
+  const Method(this._value);
   const Method.fromJson(this._value);
 
   final String _value;
 
   static bool canParse(Object obj) {
-    switch (obj) {
-      case r'$/cancelRequest':
-      case r'initialize':
-      case r'initialized':
-      case r'shutdown':
-      case r'exit':
-      case r'window/showMessage':
-      case r'window/showMessageRequest':
-      case r'window/logMessage':
-      case r'telemetry/event':
-      case r'client/registerCapability':
-      case r'client/unregisterCapability':
-      case r'workspace/workspaceFolders':
-      case r'workspace/didChangeWorkspaceFolders':
-      case r'workspace/configuration':
-      case r'workspace/didChangeWatchedFiles':
-      case r'workspace/symbol':
-      case r'workspace/executeCommand':
-      case r'workspace/applyEdit':
-      case r'textDocument/didOpen':
-      case r'textDocument/didChange':
-      case r'textDocument/willSave':
-      case r'textDocument/willSaveWaitUntil':
-      case r'textDocument/didClose':
-      case r'textDocument/publishDiagnostics':
-      case r'textDocument/completion':
-      case r'completionItem/resolve':
-      case r'textDocument/hover':
-      case r'textDocument/signatureHelp':
-      case r'textDocument/declaration':
-      case r'textDocument/definition':
-      case r'textDocument/typeDefinition':
-      case r'textDocument/implementation':
-      case r'textDocument/references':
-      case r'textDocument/documentHighlight':
-      case r'textDocument/documentSymbol':
-      case r'textDocument/codeAction':
-      case r'textDocument/codeLens':
-      case r'codeLens/resolve':
-      case r'textDocument/documentLink':
-      case r'documentLink/resolve':
-      case r'textDocument/documentColor':
-      case r'textDocument/colorPresentation':
-      case r'textDocument/formatting':
-      case r'textDocument/onTypeFormatting':
-      case r'textDocument/rename':
-      case r'textDocument/prepareRename':
-      case r'textDocument/foldingRange':
-        return true;
-    }
-    return false;
+    return obj is String;
   }
 
   /// Constant for the '$/cancelRequest' method.
-  static const cancelRequest = const Method._(r'$/cancelRequest');
+  static const cancelRequest = const Method(r'$/cancelRequest');
 
   /// Constant for the 'initialize' method.
-  static const initialize = const Method._(r'initialize');
+  static const initialize = const Method(r'initialize');
 
   /// Constant for the 'initialized' method.
-  static const initialized = const Method._(r'initialized');
+  static const initialized = const Method(r'initialized');
 
   /// Constant for the 'shutdown' method.
-  static const shutdown = const Method._(r'shutdown');
+  static const shutdown = const Method(r'shutdown');
 
   /// Constant for the 'exit' method.
-  static const exit = const Method._(r'exit');
+  static const exit = const Method(r'exit');
 
   /// Constant for the 'window/showMessage' method.
-  static const window_showMessage = const Method._(r'window/showMessage');
+  static const window_showMessage = const Method(r'window/showMessage');
 
   /// Constant for the 'window/showMessageRequest' method.
   static const window_showMessageRequest =
-      const Method._(r'window/showMessageRequest');
+      const Method(r'window/showMessageRequest');
 
   /// Constant for the 'window/logMessage' method.
-  static const window_logMessage = const Method._(r'window/logMessage');
+  static const window_logMessage = const Method(r'window/logMessage');
 
   /// Constant for the 'telemetry/event' method.
-  static const telemetry_event = const Method._(r'telemetry/event');
+  static const telemetry_event = const Method(r'telemetry/event');
 
   /// Constant for the 'client/registerCapability' method.
   static const client_registerCapability =
-      const Method._(r'client/registerCapability');
+      const Method(r'client/registerCapability');
 
   /// Constant for the 'client/unregisterCapability' method.
   static const client_unregisterCapability =
-      const Method._(r'client/unregisterCapability');
+      const Method(r'client/unregisterCapability');
 
   /// Constant for the 'workspace/workspaceFolders' method.
   static const workspace_workspaceFolders =
-      const Method._(r'workspace/workspaceFolders');
+      const Method(r'workspace/workspaceFolders');
 
   /// Constant for the 'workspace/didChangeWorkspaceFolders' method.
   static const workspace_didChangeWorkspaceFolders =
-      const Method._(r'workspace/didChangeWorkspaceFolders');
+      const Method(r'workspace/didChangeWorkspaceFolders');
 
   /// Constant for the 'workspace/configuration' method.
   static const workspace_configuration =
-      const Method._(r'workspace/configuration');
+      const Method(r'workspace/configuration');
 
   /// Constant for the 'workspace/didChangeWatchedFiles' method.
   static const workspace_didChangeWatchedFiles =
-      const Method._(r'workspace/didChangeWatchedFiles');
+      const Method(r'workspace/didChangeWatchedFiles');
 
   /// Constant for the 'workspace/symbol' method.
-  static const workspace_symbol = const Method._(r'workspace/symbol');
+  static const workspace_symbol = const Method(r'workspace/symbol');
 
   /// Constant for the 'workspace/executeCommand' method.
   static const workspace_executeCommand =
-      const Method._(r'workspace/executeCommand');
+      const Method(r'workspace/executeCommand');
 
   /// Constant for the 'workspace/applyEdit' method.
-  static const workspace_applyEdit = const Method._(r'workspace/applyEdit');
+  static const workspace_applyEdit = const Method(r'workspace/applyEdit');
 
   /// Constant for the 'textDocument/didOpen' method.
-  static const textDocument_didOpen = const Method._(r'textDocument/didOpen');
+  static const textDocument_didOpen = const Method(r'textDocument/didOpen');
 
   /// Constant for the 'textDocument/didChange' method.
-  static const textDocument_didChange =
-      const Method._(r'textDocument/didChange');
+  static const textDocument_didChange = const Method(r'textDocument/didChange');
 
   /// Constant for the 'textDocument/willSave' method.
-  static const textDocument_willSave = const Method._(r'textDocument/willSave');
+  static const textDocument_willSave = const Method(r'textDocument/willSave');
 
   /// Constant for the 'textDocument/willSaveWaitUntil' method.
   static const textDocument_willSaveWaitUntil =
-      const Method._(r'textDocument/willSaveWaitUntil');
+      const Method(r'textDocument/willSaveWaitUntil');
 
   /// Constant for the 'textDocument/didClose' method.
-  static const textDocument_didClose = const Method._(r'textDocument/didClose');
+  static const textDocument_didClose = const Method(r'textDocument/didClose');
 
   /// Constant for the 'textDocument/publishDiagnostics' method.
   static const textDocument_publishDiagnostics =
-      const Method._(r'textDocument/publishDiagnostics');
+      const Method(r'textDocument/publishDiagnostics');
 
   /// Constant for the 'textDocument/completion' method.
   static const textDocument_completion =
-      const Method._(r'textDocument/completion');
+      const Method(r'textDocument/completion');
 
   /// Constant for the 'completionItem/resolve' method.
-  static const completionItem_resolve =
-      const Method._(r'completionItem/resolve');
+  static const completionItem_resolve = const Method(r'completionItem/resolve');
 
   /// Constant for the 'textDocument/hover' method.
-  static const textDocument_hover = const Method._(r'textDocument/hover');
+  static const textDocument_hover = const Method(r'textDocument/hover');
 
   /// Constant for the 'textDocument/signatureHelp' method.
   static const textDocument_signatureHelp =
-      const Method._(r'textDocument/signatureHelp');
+      const Method(r'textDocument/signatureHelp');
 
   /// Constant for the 'textDocument/declaration' method.
   static const textDocument_declaration =
-      const Method._(r'textDocument/declaration');
+      const Method(r'textDocument/declaration');
 
   /// Constant for the 'textDocument/definition' method.
   static const textDocument_definition =
-      const Method._(r'textDocument/definition');
+      const Method(r'textDocument/definition');
 
   /// Constant for the 'textDocument/typeDefinition' method.
   static const textDocument_typeDefinition =
-      const Method._(r'textDocument/typeDefinition');
+      const Method(r'textDocument/typeDefinition');
 
   /// Constant for the 'textDocument/implementation' method.
   static const textDocument_implementation =
-      const Method._(r'textDocument/implementation');
+      const Method(r'textDocument/implementation');
 
   /// Constant for the 'textDocument/references' method.
   static const textDocument_references =
-      const Method._(r'textDocument/references');
+      const Method(r'textDocument/references');
 
   /// Constant for the 'textDocument/documentHighlight' method.
   static const textDocument_documentHighlight =
-      const Method._(r'textDocument/documentHighlight');
+      const Method(r'textDocument/documentHighlight');
 
   /// Constant for the 'textDocument/documentSymbol' method.
   static const textDocument_documentSymbol =
-      const Method._(r'textDocument/documentSymbol');
+      const Method(r'textDocument/documentSymbol');
 
   /// Constant for the 'textDocument/codeAction' method.
   static const textDocument_codeAction =
-      const Method._(r'textDocument/codeAction');
+      const Method(r'textDocument/codeAction');
 
   /// Constant for the 'textDocument/codeLens' method.
-  static const textDocument_codeLens = const Method._(r'textDocument/codeLens');
+  static const textDocument_codeLens = const Method(r'textDocument/codeLens');
 
   /// Constant for the 'codeLens/resolve' method.
-  static const codeLens_resolve = const Method._(r'codeLens/resolve');
+  static const codeLens_resolve = const Method(r'codeLens/resolve');
 
   /// Constant for the 'textDocument/documentLink' method.
   static const textDocument_documentLink =
-      const Method._(r'textDocument/documentLink');
+      const Method(r'textDocument/documentLink');
 
   /// Constant for the 'documentLink/resolve' method.
-  static const documentLink_resolve = const Method._(r'documentLink/resolve');
+  static const documentLink_resolve = const Method(r'documentLink/resolve');
 
   /// Constant for the 'textDocument/documentColor' method.
   static const textDocument_documentColor =
-      const Method._(r'textDocument/documentColor');
+      const Method(r'textDocument/documentColor');
 
   /// Constant for the 'textDocument/colorPresentation' method.
   static const textDocument_colorPresentation =
-      const Method._(r'textDocument/colorPresentation');
+      const Method(r'textDocument/colorPresentation');
 
   /// Constant for the 'textDocument/formatting' method.
   static const textDocument_formatting =
-      const Method._(r'textDocument/formatting');
+      const Method(r'textDocument/formatting');
 
   /// Constant for the 'textDocument/onTypeFormatting' method.
   static const textDocument_onTypeFormatting =
-      const Method._(r'textDocument/onTypeFormatting');
+      const Method(r'textDocument/onTypeFormatting');
 
   /// Constant for the 'textDocument/rename' method.
-  static const textDocument_rename = const Method._(r'textDocument/rename');
+  static const textDocument_rename = const Method(r'textDocument/rename');
 
   /// Constant for the 'textDocument/prepareRename' method.
   static const textDocument_prepareRename =
-      const Method._(r'textDocument/prepareRename');
+      const Method(r'textDocument/prepareRename');
 
   /// Constant for the 'textDocument/foldingRange' method.
   static const textDocument_foldingRange =
-      const Method._(r'textDocument/foldingRange');
+      const Method(r'textDocument/foldingRange');
 
   Object toJson() => _value;
 
@@ -6668,9 +6624,9 @@
   /// A number indicating the error type that occurred.
   final ErrorCodes code;
 
-  /// A Primitive or Structured value that contains additional information about
-  /// the error. Can be omitted.
-  final D data;
+  /// A string that contains additional information about the error. Can be
+  /// omitted.
+  final String data;
 
   /// A string providing a short description of the error.
   final String message;
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index a917fb1..aff4e6b 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -155,11 +155,6 @@
   final StreamController _onAnalysisSetChangedController =
       new StreamController.broadcast(sync: true);
 
-  /// The DiagnosticServer for this AnalysisServer. If available, it can be used
-  /// to start an http diagnostics server or return the port for an existing
-  /// server.
-  final DiagnosticServer diagnosticServer;
-
   final DetachableFileSystemManager detachableFileSystemManager;
 
   /// Initialize a newly created server to receive requests from and send
@@ -175,11 +170,11 @@
     AnalysisServerOptions options,
     this.sdkManager,
     this.instrumentationService, {
-    this.diagnosticServer,
+    DiagnosticServer diagnosticServer,
     ResolverProvider fileResolverProvider: null,
     ResolverProvider packageResolverProvider: null,
     this.detachableFileSystemManager: null,
-  }) : super(options, baseResourceProvider) {
+  }) : super(options, diagnosticServer, baseResourceProvider) {
     notificationManager = new NotificationManager(channel, resourceProvider);
 
     pluginManager = new PluginManager(
@@ -351,6 +346,12 @@
     });
   }
 
+  /// Return `true` if the [path] is both absolute and normalized.
+  bool isAbsoluteAndNormalized(String path) {
+    var pathContext = resourceProvider.pathContext;
+    return pathContext.isAbsolute(path) && pathContext.normalize(path) == path;
+  }
+
   /// Return `true` if analysis is complete.
   bool isAnalysisComplete() {
     return !analysisDriverScheduler.isAnalyzing;
@@ -382,6 +383,16 @@
     channel.sendResponse(response);
   }
 
+  /// If the [path] is not a valid file path, that is absolute and normalized,
+  /// send an error response, and return `true`. If OK then return `false`.
+  bool sendResponseErrorIfInvalidFilePath(Request request, String path) {
+    if (!isAbsoluteAndNormalized(path)) {
+      sendResponse(Response.invalidFilePathFormat(request, path));
+      return true;
+    }
+    return false;
+  }
+
   /// Sends a `server.error` notification.
   void sendServerErrorNotification(
     String message,
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index f784b71..b0b3d34 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/context_manager.dart';
+import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
 import 'package:analysis_server/src/services/search/element_visitors.dart';
 import 'package:analyzer/dart/analysis/results.dart';
@@ -38,6 +39,11 @@
   /// context directories.
   ContextManager contextManager;
 
+  /// The DiagnosticServer for this AnalysisServer. If available, it can be used
+  /// to start an http diagnostics server or return the port for an existing
+  /// server.
+  final DiagnosticServer diagnosticServer;
+
   /// A [RecentBuffer] of the most recent exceptions encountered by the analysis
   /// server.
   final RecentBuffer<ServerException> exceptions = new RecentBuffer(10);
@@ -73,7 +79,8 @@
   /// list is lazily created and should be accessed using [analyzedFilesGlobs].
   List<Glob> _analyzedFilesGlobs = null;
 
-  AbstractAnalysisServer(this.options, ResourceProvider baseResourceProvider)
+  AbstractAnalysisServer(this.options, this.diagnosticServer,
+      ResourceProvider baseResourceProvider)
       : resourceProvider = OverlayResourceProvider(baseResourceProvider) {
     performance = performanceDuringStartup;
   }
@@ -239,4 +246,13 @@
         .getResult(path, sendCachedToStream: sendCachedToStream)
         .catchError((_) => null);
   }
+
+  /// Return the unresolved unit for the file with the given [path].
+  ParsedUnitResult getParsedUnit(String path) {
+    if (!AnalysisEngine.isDartFileName(path)) {
+      return null;
+    }
+
+    return getAnalysisDriver(path)?.currentSession?.getParsedUnit(path);
+  }
 }
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 39c1e8e..dddc8b4 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -415,6 +415,20 @@
   }
 
   @override
+  void visitCollectionForElement(CollectionForElement node) {
+    computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
+    super.visitCollectionForElement(node);
+  }
+
+  @override
+  void visitCollectionIfElement(CollectionIfElement node) {
+    computer._addRegion_token(node.ifKeyword, HighlightRegionType.KEYWORD);
+    computer._addRegion_token(node.elseKeyword, HighlightRegionType.KEYWORD);
+    super.visitCollectionIfElement(node);
+  }
+
+  @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
     computer._addRegion_token(
         node.externalKeyword, HighlightRegionType.BUILT_IN);
@@ -475,6 +489,18 @@
   }
 
   @override
+  void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
+    computer._addRegion_token(node.inKeyword, HighlightRegionType.KEYWORD);
+    super.visitForEachPartsWithDeclaration(node);
+  }
+
+  @override
+  void visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
+    computer._addRegion_token(node.inKeyword, HighlightRegionType.KEYWORD);
+    super.visitForEachPartsWithIdentifier(node);
+  }
+
+  @override
   void visitForEachStatement(ForEachStatement node) {
     computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
     computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
@@ -489,6 +515,13 @@
   }
 
   @override
+  void visitForStatement2(ForStatement2 node) {
+    computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
+    super.visitForStatement2(node);
+  }
+
+  @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
     computer._addRegion_token(
         node.externalKeyword, HighlightRegionType.BUILT_IN);
@@ -526,6 +559,7 @@
   @override
   void visitIfStatement(IfStatement node) {
     computer._addRegion_token(node.ifKeyword, HighlightRegionType.KEYWORD);
+    computer._addRegion_token(node.elseKeyword, HighlightRegionType.KEYWORD);
     super.visitIfStatement(node);
   }
 
@@ -581,6 +615,27 @@
   }
 
   @override
+  void visitListLiteral2(ListLiteral2 node) {
+    computer._addRegion_node(node, HighlightRegionType.LITERAL_LIST);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitListLiteral2(node);
+  }
+
+  @override
+  void visitMapForElement(MapForElement node) {
+    computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
+    super.visitMapForElement(node);
+  }
+
+  @override
+  void visitMapIfElement(MapIfElement node) {
+    computer._addRegion_token(node.ifKeyword, HighlightRegionType.KEYWORD);
+    computer._addRegion_token(node.elseKeyword, HighlightRegionType.KEYWORD);
+    super.visitMapIfElement(node);
+  }
+
+  @override
   void visitMapLiteral(MapLiteral node) {
     computer._addRegion_node(node, HighlightRegionType.LITERAL_MAP);
     computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
@@ -588,6 +643,13 @@
   }
 
   @override
+  void visitMapLiteral2(MapLiteral2 node) {
+    computer._addRegion_node(node, HighlightRegionType.LITERAL_MAP);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitMapLiteral2(node);
+  }
+
+  @override
   void visitMethodDeclaration(MethodDeclaration node) {
     computer._addRegion_token(
         node.externalKeyword, HighlightRegionType.BUILT_IN);
@@ -652,6 +714,20 @@
   }
 
   @override
+  void visitSetLiteral(SetLiteral node) {
+//    computer._addRegion_node(node, HighlightRegionType.LITERAL_SET);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitSetLiteral(node);
+  }
+
+  @override
+  void visitSetLiteral2(SetLiteral2 node) {
+//    computer._addRegion_node(node, HighlightRegionType.LITERAL_SET);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitSetLiteral2(node);
+  }
+
+  @override
   void visitShowCombinator(ShowCombinator node) {
     computer._addRegion_token(node.keyword, HighlightRegionType.BUILT_IN);
     super.visitShowCombinator(node);
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
index 6ae85e2..aaea61e 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
@@ -506,6 +506,20 @@
   }
 
   @override
+  void visitCollectionForElement(CollectionForElement node) {
+    computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
+    super.visitCollectionForElement(node);
+  }
+
+  @override
+  void visitCollectionIfElement(CollectionIfElement node) {
+    computer._addRegion_token(node.ifKeyword, HighlightRegionType.KEYWORD);
+    computer._addRegion_token(node.elseKeyword, HighlightRegionType.KEYWORD);
+    super.visitCollectionIfElement(node);
+  }
+
+  @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
     computer._addRegion_token(
         node.externalKeyword, HighlightRegionType.BUILT_IN);
@@ -566,6 +580,18 @@
   }
 
   @override
+  void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
+    computer._addRegion_token(node.inKeyword, HighlightRegionType.KEYWORD);
+    super.visitForEachPartsWithDeclaration(node);
+  }
+
+  @override
+  void visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
+    computer._addRegion_token(node.inKeyword, HighlightRegionType.KEYWORD);
+    super.visitForEachPartsWithIdentifier(node);
+  }
+
+  @override
   void visitForEachStatement(ForEachStatement node) {
     computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
     computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
@@ -580,6 +606,13 @@
   }
 
   @override
+  void visitForStatement2(ForStatement2 node) {
+    computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
+    super.visitForStatement2(node);
+  }
+
+  @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
     computer._addRegion_token(
         node.externalKeyword, HighlightRegionType.BUILT_IN);
@@ -617,6 +650,7 @@
   @override
   void visitIfStatement(IfStatement node) {
     computer._addRegion_token(node.ifKeyword, HighlightRegionType.KEYWORD);
+    computer._addRegion_token(node.elseKeyword, HighlightRegionType.KEYWORD);
     super.visitIfStatement(node);
   }
 
@@ -678,6 +712,27 @@
   }
 
   @override
+  void visitListLiteral2(ListLiteral2 node) {
+    computer._addRegion_node(node, HighlightRegionType.LITERAL_LIST);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitListLiteral2(node);
+  }
+
+  @override
+  void visitMapForElement(MapForElement node) {
+    computer._addRegion_token(node.awaitKeyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.forKeyword, HighlightRegionType.KEYWORD);
+    super.visitMapForElement(node);
+  }
+
+  @override
+  void visitMapIfElement(MapIfElement node) {
+    computer._addRegion_token(node.ifKeyword, HighlightRegionType.KEYWORD);
+    computer._addRegion_token(node.elseKeyword, HighlightRegionType.KEYWORD);
+    super.visitMapIfElement(node);
+  }
+
+  @override
   void visitMapLiteral(MapLiteral node) {
     computer._addRegion_node(node, HighlightRegionType.LITERAL_MAP);
     computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
@@ -685,6 +740,13 @@
   }
 
   @override
+  void visitMapLiteral2(MapLiteral2 node) {
+    computer._addRegion_node(node, HighlightRegionType.LITERAL_MAP);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitMapLiteral2(node);
+  }
+
+  @override
   void visitMethodDeclaration(MethodDeclaration node) {
     computer._addRegion_token(
         node.externalKeyword, HighlightRegionType.BUILT_IN);
@@ -749,6 +811,20 @@
   }
 
   @override
+  void visitSetLiteral(SetLiteral node) {
+//    computer._addRegion_node(node, HighlightRegionType.LITERAL_SET);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitSetLiteral(node);
+  }
+
+  @override
+  void visitSetLiteral2(SetLiteral2 node) {
+//    computer._addRegion_node(node, HighlightRegionType.LITERAL_SET);
+    computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD);
+    super.visitSetLiteral2(node);
+  }
+
+  @override
   void visitShowCombinator(ShowCombinator node) {
     computer._addRegion_token(node.keyword, HighlightRegionType.BUILT_IN);
     super.visitShowCombinator(node);
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 9d2cbe9..6886c65 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -47,6 +47,11 @@
    */
   Future<void> getErrors(Request request) async {
     String file = new AnalysisGetErrorsParams.fromRequest(request).file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     ResolvedUnitResult result = await server.getResolvedUnit(file);
 
     if (result?.state != ResultState.VALID) {
@@ -70,9 +75,14 @@
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
     var params = new AnalysisGetHoverParams.fromRequest(request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
 
     // Prepare the resolved units.
-    ResolvedUnitResult result = await server.getResolvedUnit(params.file);
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
     CompilationUnit unit = result?.unit;
 
     // Prepare the hovers.
@@ -96,12 +106,17 @@
   Future<void> getImportedElements(Request request) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
-    AnalysisGetImportedElementsParams params =
-        new AnalysisGetImportedElementsParams.fromRequest(request);
+    var params = new AnalysisGetImportedElementsParams.fromRequest(request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     //
     // Prepare the resolved unit.
     //
-    ResolvedUnitResult result = await server.getResolvedUnit(params.file);
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
     if (result?.state != ResultState.VALID) {
       server.sendResponse(new Response.getImportedElementsInvalidFile(request));
       return;
@@ -160,6 +175,10 @@
     int offset = params.offset;
     int length = params.length;
 
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     AnalysisDriver driver = server.getAnalysisDriver(file);
     if (driver == null) {
       server.sendResponse(new Response.getNavigationInvalidFile(request));
@@ -242,9 +261,14 @@
    */
   Future<void> getSignature(Request request) async {
     var params = new AnalysisGetSignatureParams.fromRequest(request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
 
     // Prepare the resolved units.
-    ResolvedUnitResult result = await server.getResolvedUnit(params.file);
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
 
     if (result?.state != ResultState.VALID) {
       server.sendResponse(new Response.getSignatureInvalidFile(request));
@@ -388,6 +412,12 @@
   Response setPriorityFiles(Request request) {
     var params = new AnalysisSetPriorityFilesParams.fromRequest(request);
 
+    for (var file in params.files) {
+      if (!server.isAbsoluteAndNormalized(file)) {
+        return Response.invalidFilePathFormat(request, file);
+      }
+    }
+
     if (server.options.enableUXExperiment1) {
       // If this experiment is enabled, set the analysis root to be the
       // containing directory.
@@ -445,6 +475,15 @@
    */
   Response setSubscriptions(Request request) {
     var params = new AnalysisSetSubscriptionsParams.fromRequest(request);
+
+    for (var fileList in params.subscriptions.values) {
+      for (var file in fileList) {
+        if (!server.isAbsoluteAndNormalized(file)) {
+          return Response.invalidFilePathFormat(request, file);
+        }
+      }
+    }
+
     // parse subscriptions
     Map<AnalysisService, Set<String>> subMap = mapMap(params.subscriptions,
         valueCallback: (List<String> subscriptions) => subscriptions.toSet());
@@ -466,6 +505,13 @@
    */
   Response updateContent(Request request) {
     var params = new AnalysisUpdateContentParams.fromRequest(request);
+
+    for (var file in params.files.keys) {
+      if (!server.isAbsoluteAndNormalized(file)) {
+        return Response.invalidFilePathFormat(request, file);
+      }
+    }
+
     server.updateContent(request.id, params.files);
     //
     // Forward the request to the plugins.
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 2b61900..c70db3b 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -170,10 +170,14 @@
     // extract and validate params
     CompletionGetSuggestionsParams params =
         new CompletionGetSuggestionsParams.fromRequest(request);
-    String filePath = params.file;
+    String file = params.file;
     int offset = params.offset;
 
-    ResolvedUnitResult result = await server.getResolvedUnit(filePath);
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
 
     if (result?.state == ResultState.VALID) {
       if (offset < 0 || offset > result.content.length) {
@@ -185,7 +189,7 @@
         return;
       }
 
-      recordRequest(performance, filePath, result.content, offset);
+      recordRequest(performance, file, result.content, offset);
     }
     CompletionRequestImpl completionRequest =
         new CompletionRequestImpl(result, offset, performance);
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 2e1f6e2..f692c76 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -165,6 +165,10 @@
     int offset = params.offset;
     int length = params.length;
 
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     List<SourceChange> changes = <SourceChange>[];
     //
     // Allow plugins to start computing assists.
@@ -228,6 +232,11 @@
     EditGetFixesParams params = new EditGetFixesParams.fromRequest(request);
     String file = params.file;
     int offset = params.offset;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     //
     // Allow plugins to start computing fixes.
     //
@@ -277,9 +286,15 @@
     server.options.analytics?.sendEvent('edit', 'getPostfixCompletion');
 
     var params = new EditGetPostfixCompletionParams.fromRequest(request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     SourceChange change;
 
-    ResolvedUnitResult result = await server.getResolvedUnit(params.file);
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
     if (result != null) {
       PostfixCompletionContext context = new PostfixCompletionContext(
         result,
@@ -303,10 +318,17 @@
   Future getStatementCompletion(Request request) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
+
     var params = new EditGetStatementCompletionParams.fromRequest(request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     SourceChange change;
 
-    ResolvedUnitResult result = await server.getResolvedUnit(params.file);
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
     if (result != null) {
       var context = new StatementCompletionContext(result, params.offset);
       StatementCompletionProcessor processor =
@@ -377,12 +399,18 @@
   Future<void> importElements(Request request) async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
-    EditImportElementsParams params =
-        new EditImportElementsParams.fromRequest(request);
+
+    var params = new EditImportElementsParams.fromRequest(request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     //
     // Prepare the resolved unit.
     //
-    ResolvedUnitResult result = await server.getResolvedUnit(params.file);
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
     if (result == null) {
       server.sendResponse(new Response.importElementsInvalidFile(request));
     }
@@ -415,9 +443,15 @@
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
     var params = new EditGetPostfixCompletionParams.fromRequest(request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     bool value = false;
 
-    ResolvedUnitResult result = await server.getResolvedUnit(params.file);
+    ResolvedUnitResult result = await server.getResolvedUnit(file);
     if (result != null) {
       var context = new PostfixCompletionContext(
         result,
@@ -452,12 +486,16 @@
     server.options.analytics?.sendEvent('edit', 'organizeDirectives');
 
     var params = new EditOrganizeDirectivesParams.fromRequest(request);
-    // prepare file
-    String file = params.file;
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
     if (!engine.AnalysisEngine.isDartFileName(file)) {
       server.sendResponse(new Response.fileNotAnalyzed(request, file));
       return;
     }
+
     // Prepare the file information.
     ResolvedUnitResult result = await server.getResolvedUnit(file);
     if (result == null) {
@@ -487,19 +525,23 @@
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
     var params = new EditSortMembersParams.fromRequest(request);
-    // prepare file
-    String file = params.file;
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
     if (!engine.AnalysisEngine.isDartFileName(file)) {
       server.sendResponse(new Response.sortMembersInvalidFile(request));
       return;
     }
+
     // Prepare the file information.
-    var driver = server.getAnalysisDriver(file);
-    ParsedUnitResult result = await driver?.parseFile(file);
+    ParsedUnitResult result = await server.getParsedUnit(file);
     if (result == null) {
       server.sendResponse(new Response.fileNotAnalyzed(request, file));
       return;
     }
+
     int fileStamp = -1;
     String code = result.content;
     CompilationUnit unit = result.unit;
@@ -560,13 +602,15 @@
   }
 
   Future _getAvailableRefactoringsImpl(Request request) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    // prepare parameters
     var params = new EditGetAvailableRefactoringsParams.fromRequest(request);
     String file = params.file;
     int offset = params.offset;
     int length = params.length;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
+
     // add refactoring kinds
     List<RefactoringKind> kinds = <RefactoringKind>[];
     // Check nodes.
@@ -731,6 +775,11 @@
         EMPTY_PROBLEM_LIST, EMPTY_PROBLEM_LIST, EMPTY_PROBLEM_LIST);
     // process the request
     var params = new EditGetRefactoringParams.fromRequest(_request);
+    var file = params.file;
+
+    if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
+      return;
+    }
 
     if (params.kind != null) {
       server.options.analytics
@@ -740,7 +789,7 @@
     runZoned(() async {
       // TODO(brianwilkerson) Determine whether this await is necessary.
       await null;
-      await _init(params.kind, params.file, params.offset, params.length);
+      await _init(params.kind, file, params.offset, params.length);
       if (initStatus.hasFatalError) {
         feedback = null;
         _sendResultResponse();
diff --git a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
index 14bad20..fc623af 100644
--- a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
@@ -1,3 +1,7 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
 import 'package:analysis_server/src/edit/edit_dartfix.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -6,6 +10,9 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 
+/// [NonNullableFix] visits each named type in a resolved compilation unit
+/// and determines whether the associated variable or parameter can be null
+/// then adds or removes a '?' trailing the named type as appropriate.
 class NonNullableFix {
   final EditDartFix dartFix;
 
@@ -62,6 +69,28 @@
   }
 
   @override
+  void visitExtendsClause(ExtendsClause node) {
+    // skip the type name associated with the extends clause
+    node.superclass?.typeArguments?.accept(this);
+  }
+
+  @override
+  void visitImplementsClause(ImplementsClause node) {
+    // skip the type names in the implements clause
+    for (TypeName typeName in node.interfaces) {
+      typeName.typeArguments?.accept(this);
+    }
+  }
+
+  @override
+  void visitOnClause(OnClause node) {
+    // skip the type name in the clause
+    for (TypeName typeName in node.superclassConstraints) {
+      typeName.typeArguments?.accept(this);
+    }
+  }
+
+  @override
   void visitTypeName(TypeName node) {
     // TODO(danrubel): Replace this braindead implementation
     // with something that determines whether or not the type should be nullable
@@ -79,4 +108,12 @@
     }
     super.visitTypeName(node);
   }
+
+  @override
+  void visitWithClause(WithClause node) {
+    // skip the type names associated with this clause
+    for (TypeName typeName in node.mixinTypes) {
+      typeName.typeArguments?.accept(this);
+    }
+  }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart b/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart
index b81c125..d412402 100644
--- a/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart
@@ -62,7 +62,9 @@
       onError: onError,
       onDone: () {
         close();
-        onDone();
+        if (onDone != null) {
+          onDone();
+        }
       },
     );
   }
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 464ab95..aaf762f 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -56,3 +56,7 @@
   ///   if it crashes 5 times in the last 180 seconds."
   static const ClientServerInconsistentState = const ErrorCodes(-32010);
 }
+
+abstract class CustomMethods {
+  static const DiagnosticServer = const Method('dart/diagnosticServer');
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart
index 4161f20..674201f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart
@@ -33,7 +33,7 @@
     final path = arguments.single;
     final docIdentifier = server.getVersionedDocumentIdentifier(path);
 
-    final result = await requireUnit(path);
+    final result = await requireResolvedUnit(path);
     return result.mapResult((result) {
       final code = result.content;
       final unit = result.unit;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
index 24c7b7d..64c5877 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
@@ -47,7 +47,7 @@
       return error(
         ServerErrorCodes.ClientFailedToApplyEdit,
         'Client failed to apply workspace edit for $commandName',
-        editResponse.error,
+        editResponse.error.toString(),
       );
     }
 
@@ -64,7 +64,7 @@
       return error(
         ServerErrorCodes.ClientFailedToApplyEdit,
         'Client failed to apply workspace edit for $commandName',
-        workspaceEdit,
+        workspaceEdit.toString(),
       );
     }
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_diagnostic_server.dart b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_diagnostic_server.dart
new file mode 100644
index 0000000..7a3dec6
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_diagnostic_server.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+
+class DiagnosticServerHandler
+    extends MessageHandler<void, DartDiagnosticServer> {
+  DiagnosticServerHandler(LspAnalysisServer server) : super(server);
+  Method get handlesMessage => CustomMethods.DiagnosticServer;
+
+  @override
+  void convertParams(Map<String, dynamic> json) => null;
+
+  @override
+  Future<ErrorOr<DartDiagnosticServer>> handle(void _) async {
+    final port = await server.diagnosticServer.getServerPort();
+    return success(new DartDiagnosticServer(port));
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 41d3014..3788e2c 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -43,7 +43,7 @@
         capabilities?.codeActionLiteralSupport?.codeActionKind?.valueSet ?? []);
 
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
 
     return unit.mapResult((unit) {
       final startOffset = toOffset(unit.lineInfo, params.range.start);
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index bc81078..1f845ef 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -60,7 +60,7 @@
 
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
     return offset.mapResult((offset) => _getItems(
           completionCapabilities,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
index c3e9246..90912c6 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
@@ -26,7 +26,7 @@
       TextDocumentPositionParams params) async {
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
 
     return offset.mapResult((offset) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
index 9f6822e..cc21c40 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
@@ -25,7 +25,7 @@
       TextDocumentPositionParams params) async {
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
 
     return offset.mapResult((requestedOffset) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
index e1fda79..7810b7f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
@@ -61,7 +61,7 @@
         symbolCapabilities?.hierarchicalDocumentSymbolSupport ?? false;
 
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     return unit.mapResult((unit) => _getSymbols(clientSupportedSymbolKinds,
         clientSupportsDocumentSymbol, path.result, unit));
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart
index f2b3579..4f3f320 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart
@@ -18,6 +18,10 @@
 
   @override
   Future<ErrorOr<void>> handle(void _) async {
+    // TODO(dantup): Spec says we should exit with a code of 1 if we had not
+    // received a shutdown request prior to exit.
+    // TODO(dantup): Probably we should add a new state for "shutting down"
+    // that refuses any more requests between shutdown and exit.
     await server.shutdown();
     return success();
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
new file mode 100644
index 0000000..96e1a4a
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/computer/computer_folding.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/mapping.dart';
+
+class FoldingHandler
+    extends MessageHandler<FoldingRangeParams, List<FoldingRange>> {
+  FoldingHandler(LspAnalysisServer server) : super(server);
+  Method get handlesMessage => Method.textDocument_foldingRange;
+
+  @override
+  FoldingRangeParams convertParams(Map<String, dynamic> json) =>
+      FoldingRangeParams.fromJson(json);
+
+  Future<ErrorOr<List<FoldingRange>>> handle(FoldingRangeParams params) async {
+    final path = pathOfDoc(params.textDocument);
+    final unit = await path.mapResult(requireUnresolvedUnit);
+
+    return unit.mapResult((unit) {
+      final lineInfo = unit.lineInfo;
+      final regions =
+          new DartUnitFoldingComputer(lineInfo, unit.unit).compute();
+
+      return success(
+        regions.map((region) => toFoldingRange(lineInfo, region)).toList(),
+      );
+    });
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
index 6fb1c2f..37d6a9d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
@@ -6,11 +6,11 @@
 
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analysis_server/src/lsp/source_edits.dart';
-import 'package:analyzer/dart/analysis/results.dart';
 
 class FormatOnTypeHandler
     extends MessageHandler<DocumentOnTypeFormattingParams, List<TextEdit>> {
@@ -21,17 +21,19 @@
   DocumentOnTypeFormattingParams convertParams(Map<String, dynamic> json) =>
       DocumentOnTypeFormattingParams.fromJson(json);
 
-  ErrorOr<List<TextEdit>> formatFile(String path, ResolvedUnitResult unit) {
-    final unformattedSource =
-        server.resourceProvider.getFile(path).readAsStringSync();
+  ErrorOr<List<TextEdit>> formatFile(String path) {
+    final file = server.resourceProvider.getFile(path);
+    if (!file.exists) {
+      return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
+    }
 
+    final unformattedSource = file.readAsStringSync();
     return success(generateEditsForFormatting(unformattedSource));
   }
 
   Future<ErrorOr<List<TextEdit>>> handle(
       DocumentOnTypeFormattingParams params) async {
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
-    return unit.mapResult((unit) => formatFile(path.result, unit));
+    return path.mapResult((path) => formatFile(path));
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
index e226bc4..b4e0b60 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
@@ -6,11 +6,11 @@
 
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analysis_server/src/lsp/source_edits.dart';
-import 'package:analyzer/dart/analysis/results.dart';
 
 class FormattingHandler
     extends MessageHandler<DocumentFormattingParams, List<TextEdit>> {
@@ -21,17 +21,19 @@
   DocumentFormattingParams convertParams(Map<String, dynamic> json) =>
       DocumentFormattingParams.fromJson(json);
 
-  ErrorOr<List<TextEdit>> formatFile(String path, ResolvedUnitResult unit) {
-    final unformattedSource =
-        server.resourceProvider.getFile(path).readAsStringSync();
+  ErrorOr<List<TextEdit>> formatFile(String path) {
+    final file = server.resourceProvider.getFile(path);
+    if (!file.exists) {
+      return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
+    }
 
+    final unformattedSource = file.readAsStringSync();
     return success(generateEditsForFormatting(unformattedSource));
   }
 
   Future<ErrorOr<List<TextEdit>>> handle(
       DocumentFormattingParams params) async {
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
-    return unit.mapResult((unit) => formatFile(path.result, unit));
+    return path.mapResult((path) => formatFile(path));
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart
index a5396e5..d9302ae 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart
@@ -26,7 +26,7 @@
   Future<ErrorOr<Hover>> handle(TextDocumentPositionParams params) async {
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
     return offset.mapResult((offset) => _getHover(unit.result, offset));
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
index e1a72f6..67ab08f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
@@ -60,10 +60,25 @@
           false,
           // Set the characters that will cause the editor to automatically
           // trigger completion.
-          // TODO(dantup): This is quite eager and may need filtering in the
-          // completion handler.
-          // See https://github.com/Dart-Code/Dart-Code/blob/c616c93c87972713454eb0518f97c0278201a99a/src/providers/dart_completion_item_provider.ts#L36
-          r'''.: =(${'"/\'''.split(''),
+          // TODO(dantup): There are several characters that we want to conditionally
+          // allow to trigger completion, but they can only be added when the completion
+          // provider is able to handle them in context:
+          //
+          //    {   trigger if being typed in a string immediately after a $
+          //    '   trigger if the opening quote for an import/export
+          //    "   trigger if the opening quote for an import/export
+          //    /   trigger if as part of a path in an import/export
+          //    \   trigger if as part of a path in an import/export
+          //    :   don't trigger when typing case expressions (`case x:`)
+          //
+          // Additionally, we need to prefix `filterText` on completion items
+          // with spaces for those that can follow whitespace (eg. `foo` in
+          // `myArg: foo`) to ensure they're not filtered away when the user
+          // types space.
+          //
+          // See https://github.com/Dart-Code/Dart-Code/blob/68d1cd271e88a785570257d487adbdec17abd6a3/src/providers/dart_completion_item_provider.ts#L36-L64
+          // for the VS Code implementation of this.
+          r'''.=($'''.split(''),
         ),
         new SignatureHelpOptions(
           // TODO(dantup): Signature help triggering is even more sensitive to
@@ -94,7 +109,7 @@
             : Either2<bool, RenameOptions>.t1(true),
         null,
         null,
-        null,
+        Either3<bool, FoldingRangeProviderOptions, dynamic>.t1(true),
         new ExecuteCommandOptions(Commands.serverSupportedCommands),
         new ServerCapabilitiesWorkspace(
             new ServerCapabilitiesWorkspaceFolders(true, true)),
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart
index f6f803f..5f3fe45 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart
@@ -31,7 +31,7 @@
   Future<ErrorOr<List<Location>>> handle(ReferenceParams params) async {
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
     return offset.mapResult(
         (offset) => _getRefererences(path.result, offset, params, unit.result));
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
index 3a9075e..5433077 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
@@ -24,7 +24,7 @@
       TextDocumentPositionParams params) async {
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
 
     return offset.mapResult((offset) async {
@@ -84,7 +84,7 @@
         params.textDocument is VersionedTextDocumentIdentifier
             ? params.textDocument
             : server.getVersionedDocumentIdentifier(path)));
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
 
     return offset.mapResult((offset) async {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
index 2fe40ef..3f3e195 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
@@ -24,7 +24,7 @@
       TextDocumentPositionParams params) async {
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireUnit);
+    final unit = await path.mapResult(requireResolvedUnit);
     final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
 
     return offset.mapResult((offset) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
index 9375b8b..36eb607 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
@@ -7,12 +7,14 @@
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:analysis_server/lsp_protocol/protocol_special.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/handlers/custom/handler_diagnostic_server.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_code_actions.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_completion.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_definition.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_document_highlights.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_document_symbols.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_execute_command.dart';
+import 'package:analysis_server/src/lsp/handlers/handler_folding.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_format_on_type.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_formatting.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_hover.dart';
@@ -64,6 +66,8 @@
     registerHandler(new WorkspaceFoldersHandler(server));
     registerHandler(new PrepareRenameHandler(server));
     registerHandler(new RenameHandler(server));
+    registerHandler(new FoldingHandler(server));
+    registerHandler(new DiagnosticServerHandler(server));
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index 9fd98d8..78684ec 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -32,13 +32,13 @@
 mixin Handler<P, R> {
   LspAnalysisServer server;
 
-  ErrorOr<R> error<R>(ErrorCodes code, String message, Object data) =>
+  ErrorOr<R> error<R>(ErrorCodes code, String message, String data) =>
       new ErrorOr<R>.error(new ResponseError(code, message, data));
 
   ErrorOr<R> failure<R>(ErrorOr<dynamic> error) =>
       new ErrorOr<R>.error(error.error);
 
-  Future<ErrorOr<ResolvedUnitResult>> requireUnit(String path) async {
+  Future<ErrorOr<ResolvedUnitResult>> requireResolvedUnit(String path) async {
     final result = await server.getResolvedUnit(path);
     if (result?.state != ResultState.VALID) {
       return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
@@ -46,6 +46,14 @@
     return success(result);
   }
 
+  ErrorOr<ParsedUnitResult> requireUnresolvedUnit(String path) {
+    final result = server.getParsedUnit(path);
+    if (result?.state != ResultState.VALID) {
+      return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
+    }
+    return success(result);
+  }
+
   ErrorOr<R> success<R>([R t]) => new ErrorOr<R>.success(t);
 }
 
@@ -85,7 +93,7 @@
   }
 
   ErrorOr<Object> failure<Object>(ErrorCodes code, String message,
-          [Object data]) =>
+          [String data]) =>
       new ErrorOr<Object>.error(new ResponseError(code, message, data));
 
   /// Handle the given [message]. If the [message] is a [RequestMessage], then the
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 925e5a7..5f99c59 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -22,6 +22,7 @@
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analysis_server/src/plugin/notification_manager.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/services/completion/completion_performance.dart'
     show CompletionPerformance;
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
@@ -141,8 +142,9 @@
     AnalysisServerOptions options,
     this.sdkManager,
     this.instrumentationService, {
+    DiagnosticServer diagnosticServer,
     ResolverProvider packageResolverProvider: null,
-  }) : super(options, baseResourceProvider) {
+  }) : super(options, diagnosticServer, baseResourceProvider) {
     messageHandler = new UninitializedStateMessageHandler(this);
     defaultContextOptions.generateImplicitErrors = false;
     defaultContextOptions.useFastaParser = options.useFastaParser;
@@ -299,16 +301,14 @@
                 errorMessage,
                 null,
               ));
-          logError(error.toString());
-          if (stackTrace != null) {
-            logError(stackTrace.toString());
-          }
+          logException(errorMessage, error, stackTrace);
         }
       });
     }, onError: error);
   }
 
-  void logError(String message) {
+  /// Logs the error on the client using window/logMessage.
+  void logErrorToClient(String message) {
     channel.sendNotification(new NotificationMessage(
       Method.window_logMessage,
       new LogMessageParams(MessageType.Error, message),
@@ -341,7 +341,7 @@
           new ResponseMessage(message.id, null, error, jsonRpcVersion));
       // Since the LSP client might not show the failed requests to the user,
       // also ensure the error is logged to the client.
-      logError(error.message);
+      logErrorToClient(error.message);
     } else if (message is ResponseMessage) {
       // For bad response messages where we can't respond with an error, send it as
       // show instead of log.
@@ -359,7 +359,7 @@
       messageHandler = new FailureStateMessageHandler(this);
 
       final message = 'An unrecoverable error occurred.';
-      logError(
+      logErrorToClient(
           '$message\n\n${error.message}\n\n${error.code}\n\n${error.data}');
 
       shutdown();
@@ -399,24 +399,28 @@
   }
 
   void sendServerErrorNotification(String message, exception, stackTrace) {
-    final fullError = new StringBuffer();
-
-    fullError.writeln(exception == null ? message : '$message: $exception');
+    message = exception == null ? message : '$message: $exception';
 
     // Show message (without stack) to the user.
-    showError(fullError.toString());
+    showError(message);
 
-    if (stackTrace != null) {
-      fullError.writeln(stackTrace.toString());
-    }
-    // Log the full message since showMessage above may be truncated or formatted
-    // badly (eg. VS Code takes the newlines out).
-    logError(fullError.toString());
+    logException(message, exception, stackTrace);
+  }
 
-    // remember the last few exceptions
+  /// Logs an exception by sending it to the client (window/logMessage) and
+  /// recording it in a buffer on the server for diagnostics.
+  void logException(String message, exception, stackTrace) {
     if (exception is CaughtException) {
       stackTrace ??= exception.stackTrace;
     }
+
+    final fullError = stackTrace == null ? message : '$message\n$stackTrace';
+
+    // Log the full message since showMessage above may be truncated or formatted
+    // badly (eg. VS Code takes the newlines out).
+    logErrorToClient(fullError);
+
+    // remember the last few exceptions
     exceptions.add(new ServerException(
       message,
       exception,
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
index 25a15e1..aee1dca 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_socket_server.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/socket_server.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
@@ -31,11 +32,12 @@
    * The function used to create a new SDK using the default SDK.
    */
   final DartSdkManager sdkManager;
-
+  final DiagnosticServer diagnosticServer;
   final InstrumentationService instrumentationService;
 
   LspSocketServer(
     this.analysisServerOptions,
+    this.diagnosticServer,
     this.sdkManager,
     this.instrumentationService,
   );
@@ -78,6 +80,7 @@
     }
 
     analysisServer = new LspAnalysisServer(serverChannel, resourceProvider,
-        analysisServerOptions, sdkManager, instrumentationService);
+        analysisServerOptions, sdkManager, instrumentationService,
+        diagnosticServer: diagnosticServer);
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index d69d15d..edf1327 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -256,7 +256,7 @@
     return new ErrorOr<String>.error(new ResponseError(
         lsp.ServerErrorCodes.InvalidFilePath,
         'URI was not a valid file:// URI',
-        uri));
+        uri.toString()));
   }
   try {
     return new ErrorOr<String>.success(uri.toFilePath());
@@ -266,7 +266,7 @@
     return new ErrorOr<String>.error(new ResponseError(
         lsp.ServerErrorCodes.InvalidFilePath,
         'File URI did not contain a valid file path',
-        uri));
+        uri.toString()));
   }
 }
 
@@ -417,6 +417,28 @@
   }
 }
 
+lsp.FoldingRange toFoldingRange(
+    server.LineInfo lineInfo, server.FoldingRegion region) {
+  final range = toRange(lineInfo, region.offset, region.length);
+  return new lsp.FoldingRange(range.start.line, range.start.character,
+      range.end.line, range.end.character, toFoldingRangeKind(region.kind));
+}
+
+lsp.FoldingRangeKind toFoldingRangeKind(server.FoldingKind kind) {
+  switch (kind) {
+    case server.FoldingKind.DOCUMENTATION_COMMENT:
+    case server.FoldingKind.FILE_HEADER:
+      return lsp.FoldingRangeKind.Comment;
+    case server.FoldingKind.DIRECTIVES:
+      return lsp.FoldingRangeKind.Imports;
+    default:
+      // null (actually undefined in LSP, the toJson() takes care of that) is
+      // valid, and actually the value used for the majority of folds
+      // (class/functions/etc.).
+      return null;
+  }
+}
+
 List<lsp.DocumentHighlight> toHighlights(
     server.LineInfo lineInfo, server.Occurrences occurrences) {
   return occurrences.offsets
@@ -436,7 +458,7 @@
             ? lsp.ServerErrorCodes.ClientServerInconsistentState
             : lsp.ServerErrorCodes.InvalidFileLineCol,
         'Invalid line number',
-        pos.line));
+        pos.line.toString()));
   }
   // TODO(dantup): Is there any way to validate the character? We could ensure
   // it's less than the offset of the next line, but that would only work for
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 29d59bb..305b455 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -554,6 +554,7 @@
 
     final socketServer = new LspSocketServer(
       analysisServerOptions,
+      diagnosticServer,
       dartSdkManager,
       instrumentationService,
     );
diff --git a/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart b/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart
index 1b5cde5..92fd980 100644
--- a/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart
+++ b/pkg/analysis_server/lib/src/server/lsp_stdio_server.dart
@@ -33,7 +33,7 @@
    */
   Future serveStdio() {
     LspByteStreamServerChannel serverChannel = new LspByteStreamServerChannel(
-        stdin, stdout, socketServer.instrumentationService);
+        stdin, stdout.nonBlocking, socketServer.instrumentationService);
     socketServer.createAnalysisServer(serverChannel);
     return serverChannel.closed;
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index f7ddb32..85c9fa6 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -280,6 +280,7 @@
       if (parameter is FieldFormalParameterElement) {
         _setDocumentation(suggestion, parameter.field?.documentationComment);
         suggestion.element = convertElement(parameter);
+        suggestion.elementUri = parameter.source.toString();
       }
 
       suggestions.add(suggestion);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
index 77b4ebf..d89ed2f 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
@@ -103,6 +103,7 @@
         suggestion.element = createLocalElement(
             request.source, protocol.ElementKind.LABEL, label.label,
             returnType: NO_RETURN_TYPE);
+        suggestion.elementUri = request.source.toString();
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index a883a59..c335b79 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -342,6 +342,7 @@
           isDeprecated: isDeprecated,
           parameters: param?.toSource(),
           returnType: typeName);
+      suggestion.elementUri = request.source.toString();
       if ((elemKind == protocol.ElementKind.METHOD ||
               elemKind == protocol.ElementKind.FUNCTION) &&
           param != null) {
@@ -383,6 +384,7 @@
             constantDeclaration.name.length,
             0,
             0));
+    suggestion.elementUri = request.source.uri.toString();
   }
 
   void _addLocalSuggestion_includeReturnValueSuggestions(
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
index aa25fba..22692c1 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
@@ -9,9 +9,7 @@
 import 'package:analysis_server/src/protocol_server.dart' as protocol
     hide CompletionSuggestion, CompletionSuggestionKind;
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
-import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -33,30 +31,29 @@
     if (targetId == null) {
       return const <CompletionSuggestion>[];
     }
-    ClassDeclaration classDecl =
-        targetId.thisOrAncestorOfType<ClassDeclaration>();
+    var classDecl = targetId.thisOrAncestorOfType<ClassOrMixinDeclaration>();
     if (classDecl == null) {
       return const <CompletionSuggestion>[];
     }
 
-    // TODO(brianwilkerson) Consider making the type system visible from the
-    // request.result.
-    var inheritance = new InheritanceManager2(
-        await request.result.libraryElement.session.typeSystem);
+    var inheritance = new InheritanceManager2(request.result.typeSystem);
 
     // Generate a collection of inherited members
-    ClassElement classElem = classDecl.declaredElement;
-    var interface = inheritance.getInterface(classElem.type).map;
-    var namesToOverride = _namesToOverride(classElem, interface.keys);
+    var classElem = classDecl.declaredElement;
+    var interface = inheritance.getInterface(classElem.type);
+    var interfaceMap = interface.map;
+    var namesToOverride =
+        _namesToOverride(classElem.librarySource.uri, interface);
 
     // Build suggestions
     List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
     for (Name name in namesToOverride) {
-      FunctionType signature = interface[name];
+      FunctionType signature = interfaceMap[name];
       // Gracefully degrade if the overridden element has not been resolved.
       if (signature.returnType != null) {
-        CompletionSuggestion suggestion =
-            await _buildSuggestion(request, targetId, signature);
+        var invokeSuper = interface.isSuperImplemented(name);
+        var suggestion =
+            await _buildSuggestion(request, targetId, signature, invokeSuper);
         if (suggestion != null) {
           suggestions.add(suggestion);
         }
@@ -66,41 +63,26 @@
   }
 
   /**
-   * Return a template for an override of the given [signature]. If selected,
-   * the template will replace [targetId].
+   * Build a suggestion to replace [targetId] in the given [request] with an
+   * override of the given [signature].
    */
-  Future<DartChangeBuilder> _buildReplacementText(
-      ResolvedUnitResult result,
+  Future<CompletionSuggestion> _buildSuggestion(
+      DartCompletionRequest request,
       SimpleIdentifier targetId,
       FunctionType signature,
-      StringBuffer displayTextBuffer) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    DartChangeBuilder builder = new DartChangeBuilder(result.session);
-    await builder.addFileEdit(result.path, (DartFileEditBuilder builder) {
-      builder.addReplacement(range.node(targetId), (DartEditBuilder builder) {
-        ExecutableElement element = signature.element;
+      bool invokeSuper) async {
+    var displayTextBuffer = new StringBuffer();
+    var builder = new DartChangeBuilder(request.result.session);
+    await builder.addFileEdit(request.result.path, (builder) {
+      builder.addReplacement(range.node(targetId), (builder) {
         builder.writeOverride(
           signature,
           displayTextBuffer: displayTextBuffer,
-          invokeSuper: !element.isAbstract,
+          invokeSuper: invokeSuper,
         );
       });
     });
-    return builder;
-  }
 
-  /**
-   * Build a suggestion to replace [targetId] in the given [unit]
-   * with an override of the given [signature].
-   */
-  Future<CompletionSuggestion> _buildSuggestion(DartCompletionRequest request,
-      SimpleIdentifier targetId, FunctionType signature) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    StringBuffer displayTextBuffer = new StringBuffer();
-    DartChangeBuilder builder = await _buildReplacementText(
-        request.result, targetId, signature, displayTextBuffer);
     String replacement = builder.sourceChange.edits[0].edits[0].replacement;
     String completion = replacement.trim();
     String overrideAnnotation = '@override';
@@ -129,6 +111,7 @@
         false,
         displayText: displayText);
     suggestion.element = protocol.convertElement(signature.element);
+    suggestion.elementUri = signature.element.source.toString();
     return suggestion;
   }
 
@@ -138,7 +121,7 @@
    */
   SimpleIdentifier _getTargetId(CompletionTarget target) {
     AstNode node = target.containingNode;
-    if (node is ClassDeclaration) {
+    if (node is ClassOrMixinDeclaration) {
       Object entity = target.entity;
       if (entity is FieldDeclaration) {
         return _getTargetIdFromVarList(entity.fields);
@@ -174,17 +157,6 @@
   }
 
   /**
-   * Return `true` if the given [classElement] directly declares a member with
-   * the given [memberName].
-   */
-  bool _hasMember(ClassElement classElement, String memberName) {
-    return classElement.getField(memberName) != null ||
-        classElement.getGetter(memberName) != null ||
-        classElement.getMethod(memberName) != null ||
-        classElement.getSetter(memberName) != null;
-  }
-
-  /**
    * Return `true` if the given [node] has an `override` annotation.
    */
   bool _hasOverride(AstNode node) {
@@ -201,16 +173,14 @@
   }
 
   /**
-   * Return a list containing the subset of [interfaceNames] that are not
-   * defined yet in the given [classElement].
+   * Return the list of names that belong to the [interface] of a class, but
+   * are not yet declared in the class.
    */
-  List<Name> _namesToOverride(
-      ClassElement classElement, Iterable<Name> interfaceNames) {
-    var libraryUri = classElement.library.source.uri;
+  List<Name> _namesToOverride(Uri libraryUri, Interface interface) {
     var namesToOverride = <Name>[];
-    for (var name in interfaceNames) {
+    for (var name in interface.map.keys) {
       if (name.isAccessibleFor(libraryUri)) {
-        if (!_hasMember(classElement, name.name)) {
+        if (!interface.declared.containsKey(name)) {
           namesToOverride.add(name);
         }
       }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 7c65f43..5f66d87 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -51,6 +51,7 @@
   suggestion.docSummary = getDartDocSummary(doc);
 
   suggestion.element = protocol.convertElement(element);
+  suggestion.elementUri = element.source.uri.toString();
   Element enclosingElement = element.enclosingElement;
   if (enclosingElement is ClassElement) {
     suggestion.declaringType = enclosingElement.displayName;
@@ -165,6 +166,7 @@
     CompletionSuggestion suggestion = createSuggestion(element,
         completion: completion, kind: kind, relevance: relevance);
     if (suggestion != null) {
+      suggestion.elementUri = element.source.uri.toString();
       if (element.isSynthetic && element is PropertyAccessorElement) {
         String cacheKey;
         if (element.isGetter) {
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 8601163..9f3595e 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -77,6 +77,10 @@
       "Convert to field formal parameter");
   static const CONVERT_TO_INT_LITERAL = const AssistKind(
       'dart.assist.convert.toIntLiteral', 30, "Convert to an int literal");
+  static const CONVERT_TO_MULTILINE_STRING = const AssistKind(
+      'dart.assist.convert.toMultilineString',
+      30,
+      "Convert to multiline string");
   static const CONVERT_TO_NORMAL_PARAMETER = const AssistKind(
       'dart.assist.convert.toConstructorNormalParameter',
       30,
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 135f6dc..001180e 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -99,6 +99,7 @@
     await _addProposal_convertToIsNot_onNot();
     await _addProposal_convertToIsNotEmpty();
     await _addProposal_convertToFieldParameter();
+    await _addProposal_convertToMultilineString();
     await _addProposal_convertToNormalParameter();
     await _addProposal_convertToSingleQuotedString();
     await _addProposal_encapsulateField();
@@ -1266,6 +1267,36 @@
     }
   }
 
+  Future<void> _addProposal_convertToMultilineString() async {
+    var node = this.node;
+    if (node is InterpolationElement) {
+      node = (node as InterpolationElement).parent;
+    }
+    if (node is SingleStringLiteral) {
+      SingleStringLiteral literal = node;
+      if (!literal.isMultiline) {
+        var changeBuilder = _newDartChangeBuilder();
+        await changeBuilder.addFileEdit(file, (builder) {
+          var newQuote = literal.isSingleQuoted ? "'''" : '"""';
+          builder.addReplacement(
+            SourceRange(literal.offset + (literal.isRaw ? 1 : 0), 1),
+            (builder) {
+              builder.writeln(newQuote);
+            },
+          );
+          builder.addSimpleReplacement(
+            SourceRange(literal.end - 1, 1),
+            newQuote,
+          );
+        });
+        _addAssistFromBuilder(
+          changeBuilder,
+          DartAssistKind.CONVERT_TO_MULTILINE_STRING,
+        );
+      }
+    }
+  }
+
   Future<void> _addProposal_convertToSingleQuotedString() async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
@@ -1625,7 +1656,7 @@
               }
               builder.writeln('  @override');
               builder.writeln('  $stateName createState() {');
-              builder.writeln('    return new $stateName();');
+              builder.writeln('    return $stateName();');
               builder.writeln('  }');
               if (hasEmptyLineAfterCreateState) {
                 builder.writeln();
@@ -1817,8 +1848,8 @@
       return;
     }
 
-    // child: new ThisWidget(child: ourChild)
-    // children: [foo, new ThisWidget(child: ourChild), bar]
+    // child: ThisWidget(child: ourChild)
+    // children: [foo, ThisWidget(child: ourChild), bar]
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
       var childExpression = childArgument.expression;
@@ -2608,7 +2639,6 @@
         builder.write('[');
         builder.write(eol);
         builder.write(indentArg);
-        builder.write('new ');
         builder.addSimpleLinkedEdit('WIDGET', 'widget');
         builder.write('(');
         builder.write(eol);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index e9bf18d..2f872621 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -201,6 +201,8 @@
       'MOVE_TYPE_ARGUMENTS_TO_CLASS',
       50,
       "Move type arguments to after class name");
+  static const REMOVE_ANNOTATION =
+      const FixKind('REMOVE_ANNOTATION', 50, "Remove the '{0}' annotation");
   static const REMOVE_AWAIT = const FixKind('REMOVE_AWAIT', 50, "Remove await");
   static const REMOVE_DEAD_CODE =
       const FixKind('REMOVE_DEAD_CODE', 50, "Remove dead code");
@@ -220,6 +222,8 @@
       "Remove unnecessary interpolation braces");
   static const REMOVE_METHOD_DECLARATION = const FixKind(
       'REMOVE_METHOD_DECLARATION', 50, "Remove method declaration");
+  static const REMOVE_NAME_FROM_COMBINATOR = const FixKind(
+      'REMOVE_NAME_FROM_COMBINATOR', 50, "Remove name from '{0}'");
   static const REMOVE_PARAMETERS_IN_GETTER_DECLARATION = const FixKind(
       'REMOVE_PARAMETERS_IN_GETTER_DECLARATION',
       50,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 0db0fb2..2d8e769 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -282,27 +282,107 @@
     if (errorCode == HintCode.DEAD_CODE) {
       await _addFix_removeDeadCode();
     }
+    if (errorCode == HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH ||
+        errorCode == HintCode.DEAD_CODE_ON_CATCH_SUBTYPE) {
+      await _addFix_removeDeadCode();
+      // TODO(brianwilkerson) Add a fix to move the unreachable catch clause to
+      //  a place where it can be reached (when possible).
+    }
+    // TODO(brianwilkerson) Define a syntax for deprecated members to indicate
+    //  how to update the code and implement a fix to apply the update.
+//    if (errorCode == HintCode.DEPRECATED_MEMBER_USE ||
+//        errorCode == HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE) {
+//      await _addFix_replaceDeprecatedMemberUse();
+//    }
     if (errorCode == HintCode.DIVISION_OPTIMIZATION) {
       await _addFix_useEffectiveIntegerDivision();
     }
+    if (errorCode == HintCode.DUPLICATE_IMPORT) {
+      await _addFix_removeUnusedImport();
+    }
+    if (errorCode == HintCode.DUPLICATE_HIDDEN_NAME ||
+        errorCode == HintCode.DUPLICATE_SHOWN_NAME) {
+      await _addFix_removeNameFromCombinator();
+    }
+    // TODO(brianwilkerson) Add a fix to convert the path to a package: import.
+//    if (errorCode == HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE) {
+//      await _addFix_convertPathToPackageUri();
+//    }
+    if (errorCode == HintCode.INVALID_FACTORY_ANNOTATION ||
+        errorCode == HintCode.INVALID_IMMUTABLE_ANNOTATION ||
+        errorCode == HintCode.INVALID_LITERAL_ANNOTATION ||
+        errorCode == HintCode.INVALID_REQUIRED_PARAM ||
+        errorCode == HintCode.INVALID_SEALED_ANNOTATION) {
+      await _addFix_removeAnnotation();
+    }
+    if (errorCode == HintCode.MISSING_REQUIRED_PARAM ||
+        errorCode == HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS) {
+      await _addFix_addMissingRequiredArgument();
+    }
+    if (errorCode == HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER ||
+        errorCode == HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD ||
+        errorCode == HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD ||
+        errorCode == HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER) {
+      await _addFix_removeAnnotation();
+    }
+    // TODO(brianwilkerson) Add a fix to normalize the path.
+//    if (errorCode == HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT) {
+//      await _addFix_normalizeUri();
+//    }
+    if (errorCode == HintCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE) {
+      await _addFix_importAsync();
+      await _addFix_updateSdkConstraints();
+    }
     if (errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL) {
       await _addFix_isNotNull();
     }
     if (errorCode == HintCode.TYPE_CHECK_IS_NULL) {
       await _addFix_isNull();
     }
+    if (errorCode == HintCode.UNDEFINED_HIDDEN_NAME ||
+        errorCode == HintCode.UNDEFINED_SHOWN_NAME) {
+      await _addFix_removeNameFromCombinator();
+    }
     if (errorCode == HintCode.UNNECESSARY_CAST) {
       await _addFix_removeUnnecessaryCast();
     }
+    // TODO(brianwilkerson) Add a fix to remove the method.
+//    if (errorCode == HintCode.UNNECESSARY_NO_SUCH_METHOD) {
+//      await _addFix_removeMethodDeclaration();
+//    }
+    // TODO(brianwilkerson) Add a fix to remove the type check.
+//    if (errorCode == HintCode.UNNECESSARY_TYPE_CHECK_FALSE ||
+//        errorCode == HintCode.UNNECESSARY_TYPE_CHECK_TRUE) {
+//      await _addFix_removeUnnecessaryTypeCheck();
+//    }
     if (errorCode == HintCode.UNUSED_CATCH_CLAUSE) {
       await _addFix_removeUnusedCatchClause();
     }
     if (errorCode == HintCode.UNUSED_CATCH_STACK) {
       await _addFix_removeUnusedCatchStack();
     }
+    // TODO(brianwilkerson) Add a fix to remove the declaration. Decide whether
+    //  this should be a single general fix, or multiple more specific fixes
+    //  such as [_addFix_removeMethodDeclaration].
+//    if (errorCode == HintCode.UNUSED_ELEMENT ||
+//        errorCode == HintCode.UNUSED_FIELD) {
+//      await _addFix_removeUnusedDeclaration();
+//    }
     if (errorCode == HintCode.UNUSED_IMPORT) {
       await _addFix_removeUnusedImport();
     }
+    // TODO(brianwilkerson) Add a fix to remove the label.
+//    if (errorCode == HintCode.UNUSED_LABEL) {
+//      await _addFix_removeUnusedLabel();
+//    }
+    // TODO(brianwilkerson) Add a fix to remove the local variable, either with
+    //  or without the initialization code.
+//    if (errorCode == HintCode.UNUSED_LOCAL_VARIABLE) {
+//      await _addFix_removeUnusedLocalVariable();
+//    }
+    if (errorCode == HintCode.UNUSED_SHOWN_NAME) {
+      await _addFix_removeNameFromCombinator();
+    }
     if (errorCode == ParserErrorCode.EXPECTED_TOKEN) {
       await _addFix_insertSemicolon();
     }
@@ -327,10 +407,6 @@
       await _addFix_createConstructor_insteadOfSyntheticDefault();
       await _addFix_addMissingParameter();
     }
-    if (errorCode == HintCode.MISSING_REQUIRED_PARAM ||
-        errorCode == HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS) {
-      await _addFix_addMissingRequiredArgument();
-    }
     if (errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR) {
       await _addFix_createConstructor_named();
     }
@@ -469,10 +545,6 @@
         CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE) {
       await _addFix_extendClassForMixin();
     }
-    if (errorCode == HintCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE) {
-      await _addFix_importAsync();
-      await _addFix_updateSdkConstraints();
-    }
     // lints
     if (errorCode is LintCode) {
       String name = errorCode.name;
@@ -2509,6 +2581,49 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.ADD_NE_NULL);
   }
 
+  Future<void> _addFix_removeAnnotation() async {
+    void addFix(Annotation node) async {
+      if (node == null) {
+        return;
+      }
+      Token followingToken = node.endToken.next;
+      followingToken = followingToken.precedingComments ?? followingToken;
+      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addDeletion(range.startStart(node, followingToken));
+      });
+      _addFixFromBuilder(changeBuilder, DartFixKind.REMOVE_ANNOTATION,
+          args: [node.name.name]);
+    }
+
+    Annotation findAnnotation(
+        NodeList<Annotation> metadata, String targetName) {
+      return metadata.firstWhere(
+          (annotation) => annotation.name.name == targetName,
+          orElse: () => null);
+    }
+
+    AstNode node = this.coveredNode;
+    if (node is Annotation) {
+      await addFix(node);
+    } else if (node is DefaultFormalParameter) {
+      await addFix(findAnnotation(node.parameter.metadata, 'required'));
+    } else if (node is NormalFormalParameter) {
+      await addFix(findAnnotation(node.metadata, 'required'));
+    } else if (node is DeclaredSimpleIdentifier) {
+      AstNode parent = node.parent;
+      if (parent is MethodDeclaration) {
+        await addFix(findAnnotation(parent.metadata, 'override'));
+      } else if (parent is VariableDeclaration) {
+        FieldDeclaration fieldDeclaration =
+            parent.thisOrAncestorOfType<FieldDeclaration>();
+        if (fieldDeclaration != null) {
+          await addFix(findAnnotation(fieldDeclaration.metadata, 'override'));
+        }
+      }
+    }
+  }
+
   Future<void> _addFix_removeAwait() async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
@@ -2524,8 +2639,6 @@
   }
 
   Future<void> _addFix_removeDeadCode() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode coveringNode = this.coveredNode;
     if (coveringNode is Expression) {
       AstNode parent = coveredNode.parent;
@@ -2564,6 +2677,17 @@
         builder.addDeletion(rangeToRemove);
       });
       _addFixFromBuilder(changeBuilder, DartFixKind.REMOVE_DEAD_CODE);
+    } else if (coveringNode is CatchClause) {
+      TryStatement tryStatement = coveringNode.parent;
+      NodeList<CatchClause> catchClauses = tryStatement.catchClauses;
+      int index = catchClauses.indexOf(coveringNode);
+      AstNode previous =
+          index == 0 ? tryStatement.body : catchClauses[index - 1];
+      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addDeletion(range.endEnd(previous, coveringNode));
+      });
+      _addFixFromBuilder(changeBuilder, DartFixKind.REMOVE_DEAD_CODE);
     }
   }
 
@@ -2673,6 +2797,68 @@
     }
   }
 
+  Future<void> _addFix_removeNameFromCombinator() async {
+    SourceRange rangeForCombinator(Combinator combinator) {
+      AstNode parent = combinator.parent;
+      if (parent is NamespaceDirective) {
+        NodeList<Combinator> combinators = parent.combinators;
+        if (combinators.length == 1) {
+          Token previousToken =
+              combinator.parent.findPrevious(combinator.beginToken);
+          return range.endEnd(previousToken, combinator);
+        }
+        int index = combinators.indexOf(combinator);
+        if (index < 0) {
+          return null;
+        } else if (index == combinators.length - 1) {
+          return range.endEnd(combinators[index - 1], combinator);
+        }
+        return range.startStart(combinator, combinators[index + 1]);
+      }
+      return null;
+    }
+
+    SourceRange rangeForNameInCombinator(
+        Combinator combinator, SimpleIdentifier name) {
+      NodeList<SimpleIdentifier> names;
+      if (combinator is HideCombinator) {
+        names = combinator.hiddenNames;
+      } else if (combinator is ShowCombinator) {
+        names = combinator.shownNames;
+      } else {
+        return null;
+      }
+      if (names.length == 1) {
+        return rangeForCombinator(combinator);
+      }
+      int index = names.indexOf(name);
+      if (index < 0) {
+        return null;
+      } else if (index == names.length - 1) {
+        return range.endEnd(names[index - 1], name);
+      }
+      return range.startStart(name, names[index + 1]);
+    }
+
+    AstNode node = this.coveredNode;
+    if (node is SimpleIdentifier) {
+      AstNode parent = coveredNode.parent;
+      if (parent is Combinator) {
+        SourceRange rangeToRemove = rangeForNameInCombinator(parent, node);
+        if (rangeToRemove == null) {
+          return;
+        }
+        DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+        await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+          builder.addDeletion(rangeToRemove);
+        });
+        _addFixFromBuilder(
+            changeBuilder, DartFixKind.REMOVE_NAME_FROM_COMBINATOR,
+            args: [parent is HideCombinator ? 'hide' : 'show']);
+      }
+    }
+  }
+
   Future<void> _addFix_removeParameters_inGetterDeclaration() async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index b9cdaf0..80e07cc 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -17,6 +17,7 @@
 abstract class AbstractSocketServer {
   AnalysisServerOptions get analysisServerOptions;
   AbstractAnalysisServer get analysisServer;
+  DiagnosticServer get diagnosticServer;
 }
 
 /**
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 2d94d63..d9ffdb2 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -67,17 +67,67 @@
     addPackageFile('meta', 'meta.dart', r'''
 library meta;
 
+const _AlwaysThrows alwaysThrows = const _AlwaysThrows();
+
+@deprecated
+const _Checked checked = const _Checked();
+
+const _Experimental experimental = const _Experimental();
+
+const _Factory factory = const _Factory();
+
+const Immutable immutable = const Immutable();
+
 const _IsTest isTest = const _IsTest();
 
 const _IsTestGroup isTestGroup = const _IsTestGroup();
 
+const _Literal literal = const _Literal();
+
+const _MustCallSuper mustCallSuper = const _MustCallSuper();
+
+const _OptionalTypeArgs optionalTypeArgs = const _OptionalTypeArgs();
+
+const _Protected protected = const _Protected();
+
 const Required required = const Required();
 
+const _Sealed sealed = const _Sealed();
+
+@deprecated
+const _Virtual virtual = const _Virtual();
+
+const _VisibleForOverriding visibleForOverriding =
+    const _VisibleForOverriding();
+
+const _VisibleForTesting visibleForTesting = const _VisibleForTesting();
+
+class Immutable {
+  final String reason;
+  const Immutable([this.reason]);
+}
+
 class Required {
   final String reason;
   const Required([this.reason]);
 }
 
+class _AlwaysThrows {
+  const _AlwaysThrows();
+}
+
+class _Checked {
+  const _Checked();
+}
+
+class _Experimental {
+  const _Experimental();
+}
+
+class _Factory {
+  const _Factory();
+}
+
 class _IsTest {
   const _IsTest();
 }
@@ -85,6 +135,39 @@
 class _IsTestGroup {
   const _IsTestGroup();
 }
+
+class _Literal {
+  const _Literal();
+}
+
+class _MustCallSuper {
+  const _MustCallSuper();
+}
+
+class _OptionalTypeArgs {
+  const _OptionalTypeArgs();
+}
+
+class _Protected {
+  const _Protected();
+}
+
+class _Sealed {
+  const _Sealed();
+}
+
+@deprecated
+class _Virtual {
+  const _Virtual();
+}
+
+class _VisibleForOverriding {
+  const _VisibleForOverriding();
+}
+
+class _VisibleForTesting {
+  const _VisibleForTesting();
+}
 ''');
   }
 
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
index db150ad..b32c59d 100644
--- a/pkg/analysis_server/test/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -12,6 +12,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -95,6 +96,24 @@
     }
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = _createGetErrorsRequest('test.dart');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure(requestId, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = _createGetErrorsRequest(convertPath('/foo/../bar/test.dart'));
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure(requestId, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_noErrors() async {
     addTestFile('''
 main() {
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index faadc26..7dc1119 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -10,6 +10,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -416,6 +417,26 @@
     expect(hover.parameter, 'double myParameter');
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new AnalysisGetHoverParams('test.dart', 0).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request =
+        new AnalysisGetHoverParams(convertPath('/foo/../bar/test.dart'), 0)
+            .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_localVariable_declaration() async {
     addTestFile('''
 library my.library;
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
index cc31c34..b99aa74 100644
--- a/pkg/analysis_server/test/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -9,6 +9,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../mocks.dart';
 import 'notification_navigation_test.dart';
 
 main() {
@@ -129,6 +130,25 @@
     expect(testTargets[0].kind, ElementKind.LIBRARY);
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = _createGetNavigationRequest('test.dart', 0, 0);
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure(requestId, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request =
+        _createGetNavigationRequest(convertPath('/foo/../bar/test.dart'), 0, 0);
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure(requestId, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_multipleRegions() async {
     addTestFile('''
 main() {
diff --git a/pkg/analysis_server/test/analysis/get_signature_test.dart b/pkg/analysis_server/test/analysis/get_signature_test.dart
index e91c889..4242908 100644
--- a/pkg/analysis_server/test/analysis/get_signature_test.dart
+++ b/pkg/analysis_server/test/analysis/get_signature_test.dart
@@ -11,6 +11,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -131,13 +132,6 @@
         equals(RequestErrorCode.GET_SIGNATURE_UNKNOWN_FUNCTION));
   }
 
-  test_error_file_invalid_path() async {
-    var result = await prepareRawSignatureAt(0, file: ':\\/?*');
-    expect(result.error, isNotNull);
-    expect(
-        result.error.code, equals(RequestErrorCode.GET_SIGNATURE_INVALID_FILE));
-  }
-
   test_error_file_not_analyzed() async {
     var result = await prepareRawSignatureAt(0,
         file: convertPath('/not/in/project.dart'));
@@ -407,6 +401,26 @@
     expect(result.parameters, hasLength(0));
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new AnalysisGetSignatureParams('test.dart', 0).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request =
+        new AnalysisGetSignatureParams(convertPath('/foo/../bar/test.dart'), 0)
+            .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_method_instance() async {
     addTestFile('''
 /// MyClass doc
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index 1046cbe..4aa6ddc 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -16,102 +16,13 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AnalysisNotificationHighlightsTest);
+    defineReflectiveTests(HighlightsWithControlFlowCollectionsTest);
     defineReflectiveTests(HighlightTypeTest);
   });
 }
 
 @reflectiveTest
-class AnalysisNotificationHighlightsTest extends AbstractAnalysisTest {
-  List<HighlightRegion> regions;
-
-  Completer _resultsAvailable = new Completer();
-
-  void assertHasRawRegion(HighlightRegionType type, int offset, int length) {
-    for (HighlightRegion region in regions) {
-      if (region.offset == offset &&
-          region.length == length &&
-          region.type == type) {
-        return;
-      }
-    }
-    fail('Expected to find (offset=$offset; length=$length; type=$type) in\n'
-        '${regions.join('\n')}');
-  }
-
-  void assertHasRegion(HighlightRegionType type, String search,
-      [int length = -1]) {
-    int offset = findOffset(search);
-    length = findRegionLength(search, length);
-    assertHasRawRegion(type, offset, length);
-  }
-
-  void assertHasStringRegion(HighlightRegionType type, String str) {
-    int offset = findOffset(str);
-    int length = str.length;
-    assertHasRawRegion(type, offset, length);
-  }
-
-  void assertNoRawRegion(HighlightRegionType type, int offset, int length) {
-    for (HighlightRegion region in regions) {
-      if (region.offset == offset &&
-          region.length == length &&
-          region.type == type) {
-        fail(
-            'Not expected to find (offset=$offset; length=$length; type=$type) in\n'
-            '${regions.join('\n')}');
-      }
-    }
-  }
-
-  void assertNoRegion(HighlightRegionType type, String search,
-      [int length = -1]) {
-    int offset = findOffset(search);
-    length = findRegionLength(search, length);
-    assertNoRawRegion(type, offset, length);
-  }
-
-  int findRegionLength(String search, int length) {
-    if (length == -1) {
-      length = 0;
-      while (length < search.length) {
-        int c = search.codeUnitAt(length);
-        if (length == 0 && c == '@'.codeUnitAt(0)) {
-          length++;
-          continue;
-        }
-        if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
-            c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
-            c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
-          break;
-        }
-        length++;
-      }
-    }
-    return length;
-  }
-
-  Future prepareHighlights() {
-    addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
-    return _resultsAvailable.future;
-  }
-
-  void processNotification(Notification notification) {
-    if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
-      var params = new AnalysisHighlightsParams.fromNotification(notification);
-      if (params.file == testFile) {
-        regions = params.regions;
-        _resultsAvailable.complete(null);
-      }
-    }
-  }
-
-  @override
-  void setUp() {
-    super.setUp();
-    server.options.useAnalysisHighlight2 = true;
-    createProject();
-  }
-
+class AnalysisNotificationHighlightsTest extends HighlightsTestSupport {
   test_ANNOTATION_hasArguments() async {
     addTestFile('''
 class AAA {
@@ -791,6 +702,17 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
   }
 
+  test_KEYWORD_ifElse_statement() async {
+    addTestFile('''
+f(a, b) {
+  if (a < b) {} else {}
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
   test_KEYWORD_mixin() async {
     addTestFile('''
 mixin M {}
@@ -1122,6 +1044,103 @@
     assertHasRegion(type, 'unresolved(2)');
     assertHasRegion(type, 'unresolved(3)');
   }
+}
+
+class HighlightsTestSupport extends AbstractAnalysisTest {
+  List<HighlightRegion> regions;
+
+  Completer _resultsAvailable = new Completer();
+
+  void assertHasRawRegion(HighlightRegionType type, int offset, int length) {
+    for (HighlightRegion region in regions) {
+      if (region.offset == offset &&
+          region.length == length &&
+          region.type == type) {
+        return;
+      }
+    }
+    fail('Expected to find (offset=$offset; length=$length; type=$type) in\n'
+        '${regions.join('\n')}');
+  }
+
+  void assertHasRegion(HighlightRegionType type, String search,
+      [int length = -1]) {
+    int offset = findOffset(search);
+    length = findRegionLength(search, length);
+    assertHasRawRegion(type, offset, length);
+  }
+
+  void assertHasStringRegion(HighlightRegionType type, String str) {
+    int offset = findOffset(str);
+    int length = str.length;
+    assertHasRawRegion(type, offset, length);
+  }
+
+  void assertNoRawRegion(HighlightRegionType type, int offset, int length) {
+    for (HighlightRegion region in regions) {
+      if (region.offset == offset &&
+          region.length == length &&
+          region.type == type) {
+        fail(
+            'Not expected to find (offset=$offset; length=$length; type=$type) in\n'
+            '${regions.join('\n')}');
+      }
+    }
+  }
+
+  void assertNoRegion(HighlightRegionType type, String search,
+      [int length = -1]) {
+    int offset = findOffset(search);
+    length = findRegionLength(search, length);
+    assertNoRawRegion(type, offset, length);
+  }
+
+  int findRegionLength(String search, int length) {
+    if (length == -1) {
+      length = 0;
+      while (length < search.length) {
+        int c = search.codeUnitAt(length);
+        if (length == 0 && c == '@'.codeUnitAt(0)) {
+          length++;
+          continue;
+        }
+        if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
+            c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
+            c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
+          break;
+        }
+        length++;
+      }
+    }
+    return length;
+  }
+
+  Future prepareHighlights() {
+    addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
+    return _resultsAvailable.future;
+  }
+
+  void processNotification(Notification notification) {
+    if (notification.event == SERVER_NOTIFICATION_ERROR) {
+      print('SERVER_NOTIFICATION_ERROR: ${notification.toJson()}');
+      _resultsAvailable.complete(null);
+      fail('SERVER_NOTIFICATION_ERROR');
+    }
+    if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
+      var params = new AnalysisHighlightsParams.fromNotification(notification);
+      if (params.file == testFile) {
+        regions = params.regions;
+        _resultsAvailable.complete(null);
+      }
+    }
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    server.options.useAnalysisHighlight2 = true;
+    createProject();
+  }
 
   void _addLibraryForTestPart() {
     newFile(join(testFolder, 'my_lib.dart'), content: '''
@@ -1132,6 +1151,158 @@
 }
 
 @reflectiveTest
+class HighlightsWithControlFlowCollectionsTest extends HighlightsTestSupport {
+  @override
+  void createProject({Map<String, String> packageRoots}) {
+    addAnalysisOptionsFile('''
+analyzer:
+  enable-experiment:
+    - control-flow-collections
+''');
+    super.createProject(packageRoots: packageRoots);
+  }
+
+  @failingTest
+  test_KEYWORD_awaitForIn_list() async {
+    addTestFile('''
+f(a) async {
+  return [await for(var b in a) b];
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'await');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in');
+  }
+
+  @failingTest
+  test_KEYWORD_awaitForIn_map() async {
+    addTestFile('''
+f(a, b) async {
+  return {await for(var b in a) b};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'await');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in');
+  }
+
+  @failingTest
+  test_KEYWORD_awaitForIn_set() async {
+    addTestFile('''
+f(a, b) async {
+  return {await for(var b in a) b};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'await');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in');
+  }
+
+  test_KEYWORD_const_list() async {
+    addTestFile('''
+var v = const [];
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const');
+  }
+
+  test_KEYWORD_const_map() async {
+    addTestFile('''
+var v = const {0 : 1};
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const');
+  }
+
+  test_KEYWORD_const_set() async {
+    addTestFile('''
+var v = const {0};
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const');
+  }
+
+  test_KEYWORD_if_list() async {
+    addTestFile('''
+f(a, b) {
+  return [if (a < b) 'a'];
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+  }
+
+  test_KEYWORD_if_map() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a' : 1};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+  }
+
+  test_KEYWORD_if_set() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a'};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+  }
+
+  test_KEYWORD_ifElse_list() async {
+    addTestFile('''
+f(a, b) {
+  return [if (a < b) 'a' else 'b'];
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
+  test_KEYWORD_ifElse_map() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a' : 1 else 'b' : 2};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
+  test_KEYWORD_ifElse_set() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a' else 'b'};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
+  test_LITERAL_LIST() async {
+    addTestFile('var V = <int>[1, 2, 3];');
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
+  }
+
+  test_LITERAL_MAP() async {
+    addTestFile("var V = const <int, String>{1: 'a', 2: 'b', 3: 'c'};");
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
+        "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
+  }
+}
+
+@reflectiveTest
 class HighlightTypeTest {
   void test_constructor() {
     expect(HighlightRegionType.CLASS,
diff --git a/pkg/analysis_server/test/analysis/notification_highlights_test.dart b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
index 030addf..b992bc9 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
@@ -16,101 +16,13 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AnalysisNotificationHighlightsTest);
+    defineReflectiveTests(HighlightsWithControlFlowCollectionsTest);
     defineReflectiveTests(HighlightTypeTest);
   });
 }
 
 @reflectiveTest
-class AnalysisNotificationHighlightsTest extends AbstractAnalysisTest {
-  List<HighlightRegion> regions;
-
-  Completer _resultsAvailable = new Completer();
-
-  void assertHasRawRegion(HighlightRegionType type, int offset, int length) {
-    for (HighlightRegion region in regions) {
-      if (region.offset == offset &&
-          region.length == length &&
-          region.type == type) {
-        return;
-      }
-    }
-    fail('Expected to find (offset=$offset; length=$length; type=$type) in\n'
-        '${regions.join('\n')}');
-  }
-
-  void assertHasRegion(HighlightRegionType type, String search,
-      [int length = -1]) {
-    int offset = findOffset(search);
-    length = findRegionLength(search, length);
-    assertHasRawRegion(type, offset, length);
-  }
-
-  void assertHasStringRegion(HighlightRegionType type, String str) {
-    int offset = findOffset(str);
-    int length = str.length;
-    assertHasRawRegion(type, offset, length);
-  }
-
-  void assertNoRawRegion(HighlightRegionType type, int offset, int length) {
-    for (HighlightRegion region in regions) {
-      if (region.offset == offset &&
-          region.length == length &&
-          region.type == type) {
-        fail(
-            'Not expected to find (offset=$offset; length=$length; type=$type) in\n'
-            '${regions.join('\n')}');
-      }
-    }
-  }
-
-  void assertNoRegion(HighlightRegionType type, String search,
-      [int length = -1]) {
-    int offset = findOffset(search);
-    length = findRegionLength(search, length);
-    assertNoRawRegion(type, offset, length);
-  }
-
-  int findRegionLength(String search, int length) {
-    if (length == -1) {
-      length = 0;
-      while (length < search.length) {
-        int c = search.codeUnitAt(length);
-        if (length == 0 && c == '@'.codeUnitAt(0)) {
-          length++;
-          continue;
-        }
-        if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
-            c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
-            c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
-          break;
-        }
-        length++;
-      }
-    }
-    return length;
-  }
-
-  Future prepareHighlights() {
-    addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
-    return _resultsAvailable.future;
-  }
-
-  void processNotification(Notification notification) {
-    if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
-      var params = new AnalysisHighlightsParams.fromNotification(notification);
-      if (params.file == testFile) {
-        regions = params.regions;
-        _resultsAvailable.complete(null);
-      }
-    }
-  }
-
-  @override
-  void setUp() {
-    super.setUp();
-    createProject();
-  }
-
+class AnalysisNotificationHighlightsTest extends HighlightsTestSupport {
   test_ANNOTATION_hasArguments() async {
     addTestFile('''
 class AAA {
@@ -781,6 +693,17 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
   }
 
+  test_KEYWORD_ifElse_statement() async {
+    addTestFile('''
+f(a, b) {
+  if (a < b) {} else {}
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
   test_KEYWORD_mixin() async {
     addTestFile('''
 mixin M {}
@@ -971,6 +894,102 @@
     assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
     assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
   }
+}
+
+class HighlightsTestSupport extends AbstractAnalysisTest {
+  List<HighlightRegion> regions;
+
+  Completer _resultsAvailable = new Completer();
+
+  void assertHasRawRegion(HighlightRegionType type, int offset, int length) {
+    for (HighlightRegion region in regions) {
+      if (region.offset == offset &&
+          region.length == length &&
+          region.type == type) {
+        return;
+      }
+    }
+    fail('Expected to find (offset=$offset; length=$length; type=$type) in\n'
+        '${regions.join('\n')}');
+  }
+
+  void assertHasRegion(HighlightRegionType type, String search,
+      [int length = -1]) {
+    int offset = findOffset(search);
+    length = findRegionLength(search, length);
+    assertHasRawRegion(type, offset, length);
+  }
+
+  void assertHasStringRegion(HighlightRegionType type, String str) {
+    int offset = findOffset(str);
+    int length = str.length;
+    assertHasRawRegion(type, offset, length);
+  }
+
+  void assertNoRawRegion(HighlightRegionType type, int offset, int length) {
+    for (HighlightRegion region in regions) {
+      if (region.offset == offset &&
+          region.length == length &&
+          region.type == type) {
+        fail(
+            'Not expected to find (offset=$offset; length=$length; type=$type) in\n'
+            '${regions.join('\n')}');
+      }
+    }
+  }
+
+  void assertNoRegion(HighlightRegionType type, String search,
+      [int length = -1]) {
+    int offset = findOffset(search);
+    length = findRegionLength(search, length);
+    assertNoRawRegion(type, offset, length);
+  }
+
+  int findRegionLength(String search, int length) {
+    if (length == -1) {
+      length = 0;
+      while (length < search.length) {
+        int c = search.codeUnitAt(length);
+        if (length == 0 && c == '@'.codeUnitAt(0)) {
+          length++;
+          continue;
+        }
+        if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
+            c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
+            c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
+          break;
+        }
+        length++;
+      }
+    }
+    return length;
+  }
+
+  Future prepareHighlights() {
+    addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
+    return _resultsAvailable.future;
+  }
+
+  void processNotification(Notification notification) {
+    if (notification.event == SERVER_NOTIFICATION_ERROR) {
+      print('SERVER_NOTIFICATION_ERROR: ${notification.toJson()}');
+      _resultsAvailable.complete(null);
+      fail('SERVER_NOTIFICATION_ERROR');
+    }
+    if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
+      var params = new AnalysisHighlightsParams.fromNotification(notification);
+      if (params.file == testFile) {
+        regions = params.regions;
+        _resultsAvailable.complete(null);
+      }
+    }
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    createProject();
+  }
 
   void _addLibraryForTestPart() {
     newFile(join(testFolder, 'my_lib.dart'), content: '''
@@ -981,6 +1000,158 @@
 }
 
 @reflectiveTest
+class HighlightsWithControlFlowCollectionsTest extends HighlightsTestSupport {
+  @override
+  void createProject({Map<String, String> packageRoots}) {
+    addAnalysisOptionsFile('''
+analyzer:
+  enable-experiment:
+    - control-flow-collections
+''');
+    super.createProject(packageRoots: packageRoots);
+  }
+
+  @failingTest
+  test_KEYWORD_awaitForIn_list() async {
+    addTestFile('''
+f(a) async {
+  return [await for(var b in a) b];
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'await');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in');
+  }
+
+  @failingTest
+  test_KEYWORD_awaitForIn_map() async {
+    addTestFile('''
+f(a, b) async {
+  return {await for(var b in a) b};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'await');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in');
+  }
+
+  @failingTest
+  test_KEYWORD_awaitForIn_set() async {
+    addTestFile('''
+f(a, b) async {
+  return {await for(var b in a) b};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'await');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in');
+  }
+
+  test_KEYWORD_const_list() async {
+    addTestFile('''
+var v = const [];
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const');
+  }
+
+  test_KEYWORD_const_map() async {
+    addTestFile('''
+var v = const {0 : 1};
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const');
+  }
+
+  test_KEYWORD_const_set() async {
+    addTestFile('''
+var v = const {0};
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const');
+  }
+
+  test_KEYWORD_if_list() async {
+    addTestFile('''
+f(a, b) {
+  return [if (a < b) 'a'];
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+  }
+
+  test_KEYWORD_if_map() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a' : 1};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+  }
+
+  test_KEYWORD_if_set() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a'};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+  }
+
+  test_KEYWORD_ifElse_list() async {
+    addTestFile('''
+f(a, b) {
+  return [if (a < b) 'a' else 'b'];
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
+  test_KEYWORD_ifElse_map() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a' : 1 else 'b' : 2};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
+  test_KEYWORD_ifElse_set() async {
+    addTestFile('''
+f(a, b) {
+  return {if (a < b) 'a' else 'b'};
+}
+''');
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'else');
+  }
+
+  test_LITERAL_LIST_withControlFlow() async {
+    addTestFile('var V = <int>[1, 2, 3];');
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
+  }
+
+  test_LITERAL_MAP_withControlFlow() async {
+    addTestFile("var V = const <int, String>{1: 'a', 2: 'b', 3: 'c'};");
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
+        "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
+  }
+}
+
+@reflectiveTest
 class HighlightTypeTest {
   void test_constructor() {
     expect(HighlightRegionType.CLASS,
diff --git a/pkg/analysis_server/test/analysis/set_priority_files_test.dart b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
index bb6530d..dc03a1b 100644
--- a/pkg/analysis_server/test/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
@@ -31,7 +31,7 @@
   }
 
   test_fileDoesNotExist() async {
-    String file = '$projectPath/doesNotExist.dart';
+    String file = convertPath('$projectPath/doesNotExist.dart');
     Response response = await _setPriorityFile(file);
     expect(response, isResponseSuccess('0'));
   }
@@ -48,7 +48,7 @@
   test_fileInSdk() async {
     addTestFile('');
     // set priority files
-    String filePath = '/lib/convert/convert.dart';
+    String filePath = convertPath('/lib/convert/convert.dart');
     Response response = await _setPriorityFile(filePath);
     expect(response, isResponseSuccess('0'));
     // verify
@@ -56,14 +56,14 @@
   }
 
   test_fileNotInAnalysisRoot() async {
-    String path = '/other/file.dart';
+    String path = convertPath('/other/file.dart');
     newFile(path);
     await _setPriorityFile(path);
     _verifyPriorityFiles(path);
   }
 
   test_ignoredInAnalysisOptions() async {
-    String sampleFile = '$projectPath/samples/sample.dart';
+    String sampleFile = convertPath('$projectPath/samples/sample.dart');
     newFile('$projectPath/.analysis_options', content: r'''
 analyzer:
   exclude:
@@ -78,7 +78,7 @@
   test_ignoredInAnalysisOptions_inChildContext() async {
     newFile('$projectPath/.packages');
     newFile('$projectPath/child/.packages');
-    String sampleFile = '$projectPath/child/samples/sample.dart';
+    String sampleFile = convertPath('$projectPath/child/samples/sample.dart');
     newFile('$projectPath/child/.analysis_options', content: r'''
 analyzer:
   exclude:
@@ -93,7 +93,7 @@
   test_ignoredInAnalysisOptions_inRootContext() async {
     newFile('$projectPath/.packages');
     newFile('$projectPath/child/.packages');
-    String sampleFile = '$projectPath/child/samples/sample.dart';
+    String sampleFile = convertPath('$projectPath/child/samples/sample.dart');
     newFile('$projectPath/.analysis_options', content: r'''
 analyzer:
   exclude:
@@ -105,6 +105,26 @@
     _verifyPriorityFiles(sampleFile);
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request =
+        new AnalysisSetPriorityFilesParams(['test.dart']).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = new AnalysisSetPriorityFilesParams(
+        [convertPath('/foo/../bar/test.dart')]).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_sentToPlugins() async {
     addTestFile('');
     // set priority files
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index 5ab9a4e..9245872 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -14,6 +14,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -60,6 +61,28 @@
     }
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new AnalysisUpdateContentParams(
+      {'test.dart': AddContentOverlay('')},
+    ).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = new AnalysisUpdateContentParams(
+      {convertPath('/foo/../bar/test.dart'): AddContentOverlay('')},
+    ).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_multiple_contexts() async {
     String project1path = convertPath('/project1');
     String project2path = convertPath('/project2');
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index 8415bc9..6135864 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -73,6 +73,12 @@
 
   AnalysisDriver get testDiver => server.getAnalysisDriver(testFile);
 
+  void addAnalysisOptionsFile(String content) {
+    newFile(
+        resourceProvider.pathContext.join(projectPath, 'analysis_options.yaml'),
+        content: content);
+  }
+
   void addAnalysisSubscription(AnalysisService service, String file) {
     // add file to subscription
     var files = analysisSubscriptions[service];
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index e50b52f..ae88bc8 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -105,8 +105,9 @@
   }
 
   test_setPriorityFiles_invalid() {
-    var request = new AnalysisSetPriorityFilesParams(['/project/lib.dart'])
-        .toRequest('0');
+    var request = new AnalysisSetPriorityFilesParams(
+      [convertPath('/project/lib.dart')],
+    ).toRequest('0');
     var response = handler.handleRequest(request);
     expect(response, isResponseSuccess('0'));
   }
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index f22f2f2..4749ab7 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -19,6 +19,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'domain_completion_util.dart';
+import 'mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -548,6 +549,27 @@
     });
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request =
+        new CompletionGetSuggestionsParams('test.dart', 0).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = new CompletionGetSuggestionsParams(
+            convertPath('/foo/../bar/test.dart'), 0)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_invocation() {
     addTestFile('class A {b() {}} main() {A a; a.^}');
     return getSuggestions().then((_) {
diff --git a/pkg/analysis_server/test/domain_edit_dartfix_test.dart b/pkg/analysis_server/test/domain_edit_dartfix_test.dart
index edd543c..8e568e4 100644
--- a/pkg/analysis_server/test/domain_edit_dartfix_test.dart
+++ b/pkg/analysis_server/test/domain_edit_dartfix_test.dart
@@ -122,11 +122,18 @@
     createProject();
     addTestFile('''
 main() {
-  functionWithNullableParam(new List<Object>(1));
+  functionWithNullableParam(new List<String>(1));
   functionWithNullableParam(null);
 }
 
-void functionWithNullableParam(Object object) {
+class C1 {}
+class C2 {}
+class C extends C1 with M1 implements C2 {}
+
+mixin M1 {}
+mixin M on M1 implements C1 {}
+
+void functionWithNullableParam(String object) {
   if (object == null) {
     print('object is null');
   } else {
@@ -143,11 +150,18 @@
     expectSuggestion(result.suggestions[0], 'non-nullable', 46, 6);
     expectEdits(result.edits, '''
 main() {
-  functionWithNullableParam(new List<Object?>(1));
+  functionWithNullableParam(new List<String?>(1));
   functionWithNullableParam(null);
 }
 
-void functionWithNullableParam(Object? object) {
+class C1 {}
+class C2 {}
+class C extends C1 with M1 implements C2 {}
+
+mixin M1 {}
+mixin M on M1 implements C1 {}
+
+void functionWithNullableParam(String? object) {
   if (object == null) {
     print('object is null');
   } else {
diff --git a/pkg/analysis_server/test/edit/assists_test.dart b/pkg/analysis_server/test/edit/assists_test.dart
index d8a77f0..51c4da0 100644
--- a/pkg/analysis_server/test/edit/assists_test.dart
+++ b/pkg/analysis_server/test/edit/assists_test.dart
@@ -16,6 +16,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -68,6 +69,26 @@
     _assertHasChange(message, 'xmain() {}');
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new EditGetAssistsParams('test.dart', 0, 0).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request =
+        new EditGetAssistsParams(convertPath('/foo/../bar/test.dart'), 0, 0)
+            .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_removeTypeAnnotation() async {
     addTestFile('''
 main() {
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index c9c5eaa..2fa8a24 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -16,6 +16,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -43,7 +44,7 @@
         await _getFixesAt('Completer<String>');
     expect(errorFixes, hasLength(1));
     AnalysisError error = errorFixes[0].error;
-    expect(error.severity, AnalysisErrorSeverity.WARNING);
+    expect(error.severity, AnalysisErrorSeverity.ERROR);
     expect(error.type, AnalysisErrorType.STATIC_WARNING);
     List<SourceChange> fixes = errorFixes[0].fixes;
     expect(fixes, hasLength(3));
@@ -96,6 +97,26 @@
     }
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new EditGetFixesParams('test.dart', 0).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request =
+        new EditGetFixesParams(convertPath('/foo/../bar/test.dart'), 0)
+            .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_overlayOnlyFile() async {
     createProject();
     testCode = '''
diff --git a/pkg/analysis_server/test/edit/organize_directives_test.dart b/pkg/analysis_server/test/edit/organize_directives_test.dart
index e8424aa..116427e 100644
--- a/pkg/analysis_server/test/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/edit/organize_directives_test.dart
@@ -55,13 +55,34 @@
   }
 
   Future test_BAD_notDartFile() async {
-    Request request =
-        new EditOrganizeDirectivesParams('/not-a-Dart-file.txt').toRequest('0');
+    Request request = new EditOrganizeDirectivesParams(
+      convertPath('/not-a-Dart-file.txt'),
+    ).toRequest('0');
     Response response = await waitResponse(request);
     expect(
         response, isResponseFailure('0', RequestErrorCode.FILE_NOT_ANALYZED));
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new EditOrganizeDirectivesParams('test.dart').toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request =
+        new EditOrganizeDirectivesParams(convertPath('/foo/../bar/test.dart'))
+            .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   Future test_OK_remove_duplicateImports_withSamePrefix() {
     addTestFile('''
 library lib;
diff --git a/pkg/analysis_server/test/edit/postfix_completion_test.dart b/pkg/analysis_server/test/edit/postfix_completion_test.dart
index 00139e5..c8cede9 100644
--- a/pkg/analysis_server/test/edit/postfix_completion_test.dart
+++ b/pkg/analysis_server/test/edit/postfix_completion_test.dart
@@ -10,6 +10,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -45,6 +46,27 @@
 ''');
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new EditGetPostfixCompletionParams('test.dart', '.for', 0)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = new EditGetPostfixCompletionParams(
+            convertPath('/foo/../bar/test.dart'), '.for', 0)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   void _assertHasChange(String message, String expectedCode, [Function cmp]) {
     if (change.message == message) {
       if (!change.edits.isEmpty) {
diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart
index da70280..df6558d 100644
--- a/pkg/analysis_server/test/edit/refactoring_test.dart
+++ b/pkg/analysis_server/test/edit/refactoring_test.dart
@@ -352,6 +352,32 @@
 ''');
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new EditGetRefactoringParams(
+            RefactoringKind.EXTRACT_LOCAL_VARIABLE, 'test.dart', 0, 0, true)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = new EditGetRefactoringParams(
+            RefactoringKind.EXTRACT_LOCAL_VARIABLE,
+            convertPath('/foo/../bar/test.dart'),
+            0,
+            0,
+            true)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_names() async {
     addTestFile('''
 class TreeItem {}
@@ -901,6 +927,27 @@
     expect(kinds, contains(RefactoringKind.EXTRACT_WIDGET));
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new EditGetAvailableRefactoringsParams('test.dart', 0, 0)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = new EditGetAvailableRefactoringsParams(
+            convertPath('/foo/../bar/test.dart'), 0, 0)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   Future test_rename_hasElement_class() {
     return assertHasRenameRefactoring('''
 class Test {}
diff --git a/pkg/analysis_server/test/edit/sort_members_test.dart b/pkg/analysis_server/test/edit/sort_members_test.dart
index 04828b6..29c9cb9 100644
--- a/pkg/analysis_server/test/edit/sort_members_test.dart
+++ b/pkg/analysis_server/test/edit/sort_members_test.dart
@@ -55,13 +55,34 @@
   }
 
   test_BAD_notDartFile() async {
-    Request request =
-        new EditSortMembersParams('/not-a-Dart-file.txt').toRequest('0');
+    Request request = new EditSortMembersParams(
+      convertPath('/not-a-Dart-file.txt'),
+    ).toRequest('0');
     Response response = await waitResponse(request);
     expect(response,
         isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_INVALID_FILE));
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request = new EditSortMembersParams('test.dart').toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request =
+        new EditSortMembersParams(convertPath('/foo/../bar/test.dart'))
+            .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_OK_afterWaitForAnalysis() async {
     addTestFile('''
 class C {}
diff --git a/pkg/analysis_server/test/edit/statement_completion_test.dart b/pkg/analysis_server/test/edit/statement_completion_test.dart
index 50f834b..4b381be 100644
--- a/pkg/analysis_server/test/edit/statement_completion_test.dart
+++ b/pkg/analysis_server/test/edit/statement_completion_test.dart
@@ -10,6 +10,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../mocks.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -28,6 +29,27 @@
     handler = new EditDomainHandler(server);
   }
 
+  test_invalidFilePathFormat_notAbsolute() async {
+    var request =
+        new EditGetStatementCompletionParams('test.dart', 0).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
+  test_invalidFilePathFormat_notNormalized() async {
+    var request = new EditGetStatementCompletionParams(
+            convertPath('/foo/../bar/test.dart'), 0)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+    );
+  }
+
   test_plainEnterFromStart() async {
     addTestFile('''
 main() {
diff --git a/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart b/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart
new file mode 100644
index 0000000..8f21d53
--- /dev/null
+++ b/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/src/lsp/channel/lsp_byte_stream_channel.dart';
+import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:path/path.dart';
+
+import '../../lsp/server_abstract.dart';
+
+class AbstractLspAnalysisServerIntegrationTest
+    with
+        ResourceProviderMixin,
+        ClientCapabilitiesHelperMixin,
+        LspAnalysisServerTestMixin {
+  LspServerClient client;
+
+  final Map<int, Completer<ResponseMessage>> _completers = {};
+
+  @override
+  Stream<Message> get serverToClient => client.serverToClient;
+
+  @override
+  void sendNotificationToServer(NotificationMessage notification) =>
+      client.channel.sendNotification(notification);
+
+  @override
+  Future<ResponseMessage> sendRequestToServer(RequestMessage request) {
+    final completer = new Completer<ResponseMessage>();
+    final id = request.id.map(
+        (num) => num, (string) => throw 'String IDs not supported in tests');
+    _completers[id] = completer;
+
+    client.channel.sendRequest(request);
+
+    return completer.future;
+  }
+
+  @override
+  void sendResponseToServer(ResponseMessage response) =>
+      client.channel.sendResponse(response);
+
+  Future setUp() async {
+    client = new LspServerClient();
+    await client.start();
+    client.serverToClient.listen((message) {
+      if (message is ResponseMessage) {
+        final id = message.id.map((num) => num,
+            (string) => throw 'String IDs not supported in tests');
+
+        final completer = _completers[id];
+        if (completer == null) {
+          throw 'Response with ID $id was unexpected';
+        } else {
+          _completers.remove(id);
+          completer.complete(message);
+        }
+      }
+    });
+  }
+
+  tearDown() {
+    // TODO(dantup): Graceful shutdown?
+    client.close();
+  }
+}
+
+class LspServerClient {
+  Process _process;
+  LspByteStreamServerChannel channel;
+  final StreamController<Message> _serverToClient =
+      new StreamController<Message>.broadcast();
+
+  Future<int> get exitCode => _process.exitCode;
+
+  Stream<Message> get serverToClient => _serverToClient.stream;
+
+  void close() {
+    channel.close();
+    _process.kill();
+  }
+
+  /**
+   * Find the root directory of the analysis_server package by proceeding
+   * upward to the 'test' dir, and then going up one more directory.
+   */
+  String findRoot(String pathname) {
+    while (!['benchmark', 'test'].contains(basename(pathname))) {
+      String parent = dirname(pathname);
+      if (parent.length >= pathname.length) {
+        throw new Exception("Can't find root directory");
+      }
+      pathname = parent;
+    }
+    return dirname(pathname);
+  }
+
+  Future start() async {
+    if (_process != null) {
+      throw new Exception('Process already started');
+    }
+
+    String dartBinary = Platform.executable;
+
+    // TODO(dantup): The other servers integration tests can run with a snapshot
+    // which is much faster - we may wish to investigate doing the same here.
+    final rootDir =
+        findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
+    final serverPath = normalize(join(rootDir, 'bin', 'server.dart'));
+
+    final arguments = [serverPath, '--lsp', '--suppress-analytics'];
+    _process = await Process.start(dartBinary, arguments);
+    _process.exitCode.then((int code) {
+      if (code != 0) {
+        // TODO(dantup): Log/fail tests...
+      }
+    });
+
+    channel = new LspByteStreamServerChannel(
+        _process.stdout, _process.stdin, InstrumentationService.NULL_SERVICE);
+    channel.listen(_serverToClient.add);
+  }
+}
diff --git a/pkg/analysis_server/test/integration/lsp_server/server_test.dart b/pkg/analysis_server/test/integration/lsp_server/server_test.dart
new file mode 100644
index 0000000..0e3c8c0
--- /dev/null
+++ b/pkg/analysis_server/test/integration/lsp_server/server_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'integration_tests.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ServerTest);
+  });
+}
+
+@reflectiveTest
+class ServerTest extends AbstractLspAnalysisServerIntegrationTest {
+  test_exit_afterShutdown() async {
+    await sendShutdown();
+    sendExit();
+
+    await client.channel.closed.timeout(const Duration(seconds: 10),
+        onTimeout: () =>
+            fail('Server channel did not close within 10 seconds'));
+
+    final exitCode = await client.exitCode.timeout(const Duration(seconds: 10),
+        onTimeout: () => fail('Server process did not exit within 10 seconds'));
+
+    expect(exitCode, equals(0));
+  }
+
+  @failingTest
+  test_exit_withoutShutdown() async {
+    sendExit();
+
+    await client.channel.closed.timeout(const Duration(seconds: 10),
+        onTimeout: () =>
+            fail('Server channel did not close within 10 seconds'));
+
+    final exitCode = await client.exitCode.timeout(const Duration(seconds: 10),
+        onTimeout: () => fail('Server process did not exit within 10 seconds'));
+
+    // TODO(dantup): Fix the server so this works.
+    expect(exitCode, equals(1));
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/folding_test.dart b/pkg/analysis_server/test/lsp/folding_test.dart
new file mode 100644
index 0000000..0b41612
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/folding_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'server_abstract.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FoldingTest);
+  });
+}
+
+@reflectiveTest
+class FoldingTest extends AbstractLspAnalysisServerTest {
+  test_class() async {
+    final content = '''
+    class MyClass2 {[[
+      // Class content
+    ]]}
+    ''';
+
+    final range1 = rangeFromMarkers(content);
+    final expectedRegions = [
+      new FoldingRange(
+        range1.start.line,
+        range1.start.character,
+        range1.end.line,
+        range1.end.character,
+        null,
+      )
+    ];
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final regions = await getFoldingRegions(mainFileUri);
+    expect(regions, unorderedEquals(expectedRegions));
+  }
+
+  test_comments() async {
+    final content = '''
+    [[/// This is a comment
+    /// that spans many lines]]
+    class MyClass2 {}
+    ''';
+
+    final range1 = rangeFromMarkers(content);
+    final expectedRegions = [
+      new FoldingRange(
+        range1.start.line,
+        range1.start.character,
+        range1.end.line,
+        range1.end.character,
+        FoldingRangeKind.Comment,
+      )
+    ];
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final regions = await getFoldingRegions(mainFileUri);
+    expect(regions, unorderedEquals(expectedRegions));
+  }
+
+  test_headersImportsComments() async {
+    // TODO(dantup): Review why the file header and the method comment ranges
+    // are different... one spans only the range to collapse, but the other
+    // just starts at the logical block.
+    // The LSP spec doesn't give any guidance on whether the first part of
+    // the surrounded content should be visible or not after folding
+    // so we'll need to revisit this once there's clarification:
+    // https://github.com/Microsoft/language-server-protocol/issues/659
+    final content = '''
+    // Copyright some year by some people[[
+    // See LICENCE etc.]]
+
+    import[[ 'dart:io';
+    import 'dart:async';]]
+
+    [[/// This is not the file header
+    /// It's just a comment]]
+    main() {}
+    ''';
+
+    final ranges = rangesFromMarkers(content);
+
+    final expectedRegions = [
+      _toFoldingRange(ranges[0], FoldingRangeKind.Comment),
+      _toFoldingRange(ranges[1], FoldingRangeKind.Imports),
+      _toFoldingRange(ranges[2], FoldingRangeKind.Comment),
+    ];
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final regions = await getFoldingRegions(mainFileUri);
+    expect(regions, unorderedEquals(expectedRegions));
+  }
+
+  FoldingRange _toFoldingRange(Range range, FoldingRangeKind kind) {
+    return new FoldingRange(
+      range.start.line,
+      range.start.character,
+      range.end.line,
+      range.end.character,
+      kind,
+    );
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index 7afb2a5..edbad6e 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -66,7 +66,7 @@
   test_uninitialized_dropsNotifications() async {
     final notification =
         makeNotification(new Method.fromJson('randomNotification'), null);
-    final nextNotification = channel.errorNotificationsFromServer.first;
+    final nextNotification = errorNotificationsFromServer.first;
     channel.sendNotificationToServer(notification);
 
     // Wait up to 1sec to ensure no error/log notifications were sent back.
diff --git a/pkg/analysis_server/test/lsp/rename_test.dart b/pkg/analysis_server/test/lsp/rename_test.dart
index 6226b60..2406dbb 100644
--- a/pkg/analysis_server/test/lsp/rename_test.dart
+++ b/pkg/analysis_server/test/lsp/rename_test.dart
@@ -17,11 +17,6 @@
 
 @reflectiveTest
 class RenameTest extends AbstractLspAnalysisServerTest {
-  // TODO(dantup): send a rename without a version
-  // TODO(dantup): send an old version of the doc?
-  // TODO(dantup): check the version returned matches?
-  // TODO(dantup): renames across multiple files
-
   test_prepare_class() {
     const content = '''
     class MyClass {}
@@ -122,6 +117,23 @@
         content, 'MyNewClass', expectedContent);
   }
 
+  test_rename_withoutVersionedIdentifier() {
+    // Without sending a document version, the rename should still work because
+    // the server should use the version it had at the start of the rename
+    // operation.
+    const content = '''
+    class MyClass {}
+    final a = new [[My^Class]]();
+    ''';
+    const expectedContent = '''
+    class MyNewClass {}
+    final a = new MyNewClass();
+    ''';
+    return _test_rename_withDocumentChanges(
+        content, 'MyNewClass', expectedContent,
+        sendRenameVersion: false);
+  }
+
   test_rename_classNewKeyword() async {
     const content = '''
     class MyClass {}
@@ -321,16 +333,25 @@
   }
 
   _test_rename_withDocumentChanges(
-      String content, String newName, String expectedContent) async {
+    String content,
+    String newName,
+    String expectedContent, {
+    sendDocumentVersion = true,
+    sendRenameVersion = true,
+  }) async {
+    // The specific number doesn't matter here, it's just a placeholder to confirm
+    // the values match.
+    final documentVersion = 222;
     await initialize(
       workspaceCapabilities:
           withDocumentChangesSupport(emptyWorkspaceClientCapabilities),
     );
-    await openFile(mainFileUri, withoutMarkers(content), version: 222);
+    await openFile(mainFileUri, withoutMarkers(content),
+        version: sendDocumentVersion ? documentVersion : null);
 
     final result = await rename(
       mainFileUri,
-      222,
+      sendRenameVersion ? documentVersion : null,
       positionFromMarker(content),
       newName,
     );
@@ -341,8 +362,70 @@
       final contents = {
         mainFilePath: withoutMarkers(content),
       };
-      applyDocumentChanges(contents, result.documentChanges);
+      final documentVersions = {
+        mainFilePath: documentVersion,
+      };
+      applyDocumentChanges(
+        contents,
+        result.documentChanges,
+        expectedVersions: documentVersions,
+      );
       expect(contents[mainFilePath], equals(expectedContent));
     }
   }
+
+  test_rename_multipleFiles() async {
+    final referencedFilePath =
+        join(projectFolderPath, 'lib', 'referenced.dart');
+    final referencedFileUri = Uri.file(referencedFilePath);
+    const mainContent = '''
+    import 'referenced.dart';
+    final a = new My^Class();
+    ''';
+    const referencedContent = '''
+    class MyClass {}
+    ''';
+    const expectedMainContent = '''
+    import 'referenced.dart';
+    final a = new MyNewClass();
+    ''';
+    const expectedReferencedContent = '''
+    class MyNewClass {}
+    ''';
+    const mainVersion = 111;
+    const referencedVersion = 222;
+
+    await initialize(
+      workspaceCapabilities:
+          withDocumentChangesSupport(emptyWorkspaceClientCapabilities),
+    );
+    await openFile(mainFileUri, withoutMarkers(mainContent),
+        version: mainVersion);
+    await openFile(referencedFileUri, withoutMarkers(referencedContent),
+        version: referencedVersion);
+
+    final result = await rename(
+      mainFileUri,
+      mainVersion,
+      positionFromMarker(mainContent),
+      'MyNewClass',
+    );
+
+    // Ensure applying the changes will give us the expected content.
+    final contents = {
+      mainFilePath: withoutMarkers(mainContent),
+      referencedFilePath: withoutMarkers(referencedContent),
+    };
+    final documentVersions = {
+      mainFilePath: mainVersion,
+      referencedFilePath: referencedVersion,
+    };
+    applyDocumentChanges(
+      contents,
+      result.documentChanges,
+      expectedVersions: documentVersions,
+    );
+    expect(contents[mainFilePath], equals(expectedMainContent));
+    expect(contents[referencedFilePath], equals(expectedReferencedContent));
+  }
 }
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index fad7baf..94c60f2 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -4,9 +4,11 @@
 
 import 'dart:async';
 
+import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:analysis_server/lsp_protocol/protocol_special.dart';
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
@@ -28,8 +30,8 @@
 
 final beginningOfDocument = new Range(new Position(0, 0), new Position(0, 0));
 
-abstract class AbstractLspAnalysisServerTest
-    with ResourceProviderMixin, ClientCapabilitiesHelperMixin {
+mixin LspAnalysisServerTestMixin
+    implements ResourceProviderMixin, ClientCapabilitiesHelperMixin {
   static const positionMarker = '^';
   static const rangeMarkerStart = '[[';
   static const rangeMarkerEnd = ']]';
@@ -37,13 +39,46 @@
   static final allMarkersPattern =
       new RegExp(allMarkers.map(RegExp.escape).join('|'));
 
-  MockLspServerChannel channel;
-  LspAnalysisServer server;
-
   int _id = 0;
   String projectFolderPath, mainFilePath;
   Uri projectFolderUri, mainFileUri;
 
+  Stream<Message> get serverToClient;
+
+  /**
+   * A stream of [NotificationMessage]s from the server that may be errors.
+   */
+  Stream<NotificationMessage> get errorNotificationsFromServer {
+    return notificationsFromServer.where(_isErrorNotification);
+  }
+
+  /**
+   * A stream of [NotificationMessage]s from the server.
+   */
+  Stream<NotificationMessage> get notificationsFromServer {
+    return serverToClient
+        .where((m) => m is NotificationMessage)
+        .cast<NotificationMessage>();
+  }
+
+  /// Checks whether a notification is likely an error from the server (for
+  /// example a window/showMessage). This is useful for tests that want to
+  /// ensure no errors come from the server in response to notifications (which
+  /// don't have their own responses).
+  bool _isErrorNotification(NotificationMessage notification) {
+    return notification.method == Method.window_logMessage ||
+        notification.method == Method.window_showMessage;
+  }
+
+  /**
+   * A stream of [RequestMessage]s from the server.
+   */
+  Stream<RequestMessage> get requestsFromServer {
+    return serverToClient
+        .where((m) => m is RequestMessage)
+        .cast<RequestMessage>();
+  }
+
   void applyChanges(
     Map<String, String> fileContents,
     Map<String, List<TextEdit>> changes,
@@ -55,13 +90,17 @@
   }
 
   void applyDocumentChanges(
-      Map<String, String> fileContents,
-      Either2<
-              List<TextDocumentEdit>,
-              List<
-                  Either4<TextDocumentEdit, CreateFile, RenameFile,
-                      DeleteFile>>>
-          documentChanges) {
+    Map<String, String> fileContents,
+    Either2<List<TextDocumentEdit>,
+            List<Either4<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>>>
+        documentChanges, {
+    Map<String, int> expectedVersions,
+  }) {
+    // If we were supplied with expected versions, ensure that all returned
+    // edits match the versions.
+    if (expectedVersions != null) {
+      expectDocumentVersions(documentChanges, expectedVersions);
+    }
     documentChanges.map(
       (edits) => applyTextDocumentEdits(fileContents, edits),
       (changes) => applyResourceChanges(fileContents, changes),
@@ -152,8 +191,7 @@
         changes,
       ),
     );
-    channel.sendNotificationToServer(notification);
-    await pumpEventQueue();
+    sendNotificationToServer(notification);
   }
 
   Future changeWorkspaceFolders({List<Uri> add, List<Uri> remove}) async {
@@ -166,8 +204,7 @@
         ),
       ),
     );
-    channel.sendNotificationToServer(notification);
-    await pumpEventQueue();
+    sendNotificationToServer(notification);
   }
 
   Future closeFile(Uri uri) async {
@@ -176,8 +213,7 @@
       new DidCloseTextDocumentParams(
           new TextDocumentIdentifier(uri.toString())),
     );
-    channel.sendNotificationToServer(notification);
-    await pumpEventQueue();
+    sendNotificationToServer(notification);
   }
 
   Future<Object> executeCommand(Command command) async {
@@ -191,11 +227,50 @@
     return expectSuccessfulResponseTo(request);
   }
 
+  void expectDocumentVersion(
+    TextDocumentEdit edit,
+    Map<String, int> expectedVersions,
+  ) {
+    final path = Uri.parse(edit.textDocument.uri).toFilePath();
+    final expectedVersion = expectedVersions[path];
+
+    if (edit.textDocument is VersionedTextDocumentIdentifier) {
+      expect(edit.textDocument.version, equals(expectedVersion));
+    } else {
+      throw 'Document identifier for $path was not versioned (expected version $expectedVersion)';
+    }
+  }
+
+  /// Validates the document versions for a set of edits match the versions in
+  /// the supplied map.
+  void expectDocumentVersions(
+    Either2<List<TextDocumentEdit>,
+            List<Either4<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>>>
+        documentChanges,
+    Map<String, int> expectedVersions,
+  ) {
+    documentChanges.map(
+      // Validate versions on simple doc edits
+      (edits) => edits
+          .forEach((edit) => expectDocumentVersion(edit, expectedVersions)),
+      // For resource changes, we only need to validate changes since
+      // creates/renames/deletes do not supply versions.
+      (changes) => changes.forEach((change) {
+            change.map(
+              (edit) => expectDocumentVersion(edit, expectedVersions),
+              (create) => {},
+              (rename) {},
+              (delete) {},
+            );
+          }),
+    );
+  }
+
   Future<T> expectErrorNotification<T>(
     FutureOr<void> f(), {
     Duration timeout = const Duration(seconds: 5),
   }) async {
-    final firstError = channel.errorNotificationsFromServer.first;
+    final firstError = errorNotificationsFromServer.first;
     await f();
 
     final notificationFromServer = await firstError.timeout(timeout);
@@ -211,7 +286,7 @@
     Duration timeout = const Duration(seconds: 5),
   }) async {
     final firstRequest =
-        channel.requestsFromServer.firstWhere((n) => n.method == method);
+        requestsFromServer.firstWhere((n) => n.method == method);
     await f();
 
     final requestFromServer = await firstRequest.timeout(timeout);
@@ -223,7 +298,7 @@
   /// Sends a request to the server and unwraps the result. Throws if the
   /// response was not successful or returned an error.
   Future<T> expectSuccessfulResponseTo<T>(RequestMessage request) async {
-    final resp = await channel.sendRequestToServer(request);
+    final resp = await sendRequestToServer(request);
     if (resp.error != null) {
       throw resp.error;
     } else {
@@ -298,6 +373,14 @@
     return expectSuccessfulResponseTo<List<Location>>(request);
   }
 
+  Future<DartDiagnosticServer> getDiagnosticServer() {
+    final request = makeRequest(
+      CustomMethods.DiagnosticServer,
+      null,
+    );
+    return expectSuccessfulResponseTo(request);
+  }
+
   Future<List<DocumentHighlight>> getDocumentHighlights(Uri uri, Position pos) {
     final request = makeRequest(
       Method.textDocument_documentHighlight,
@@ -320,6 +403,14 @@
     return expectSuccessfulResponseTo(request);
   }
 
+  Future<List<FoldingRange>> getFoldingRegions(Uri uri) {
+    final request = makeRequest(
+      Method.textDocument_foldingRange,
+      new FoldingRangeParams(new TextDocumentIdentifier(uri.toString())),
+    );
+    return expectSuccessfulResponseTo<List<FoldingRange>>(request);
+  }
+
   Future<Hover> getHover(Uri uri, Position pos) {
     final request = makeRequest(
       Method.textDocument_hover,
@@ -430,12 +521,12 @@
             ),
             null,
             workspaceFolders?.map(toWorkspaceFolder)?.toList()));
-    final response = await channel.sendRequestToServer(request);
+    final response = await sendRequestToServer(request);
     expect(response.id, equals(request.id));
 
     if (response.error == null) {
       final notification = makeNotification(Method.initialized, null);
-      channel.sendNotificationToServer(notification);
+      sendNotificationToServer(notification);
       await pumpEventQueue();
     }
 
@@ -469,7 +560,7 @@
       new DidOpenTextDocumentParams(new TextDocumentItem(
           uri.toString(), dartLanguageId, version, content)),
     );
-    channel.sendNotificationToServer(notification);
+    sendNotificationToServer(notification);
     await pumpEventQueue();
   }
 
@@ -560,7 +651,7 @@
     String newName,
   ) {
     final request = makeRenameRequest(version, uri, pos, newName);
-    return channel.sendRequestToServer(request);
+    return sendRequestToServer(request);
   }
 
   Future replaceFile(int newVersion, Uri uri, String content) {
@@ -574,10 +665,77 @@
   /// Sends [responseParams] to the server as a successful response to
   /// a server-initiated [request].
   void respondTo<T>(RequestMessage request, T responseParams) {
-    channel.sendResponseToServer(
+    sendResponseToServer(
         new ResponseMessage(request.id, responseParams, null, jsonRpcVersion));
   }
 
+  Future<Null> sendShutdown() {
+    final request = makeRequest(Method.shutdown, null);
+    return expectSuccessfulResponseTo(request);
+  }
+
+  void sendExit() {
+    final request = makeRequest(Method.exit, null);
+    sendRequestToServer(request);
+  }
+
+  FutureOr<void> sendNotificationToServer(NotificationMessage notification);
+
+  Future<ResponseMessage> sendRequestToServer(RequestMessage request);
+
+  void sendResponseToServer(ResponseMessage response);
+
+  WorkspaceFolder toWorkspaceFolder(Uri uri) {
+    return WorkspaceFolder(uri.toString(), path.basename(uri.toFilePath()));
+  }
+
+  Future<List<Diagnostic>> waitForDiagnostics(Uri uri) async {
+    PublishDiagnosticsParams diagnosticParams;
+    await serverToClient.firstWhere((message) {
+      if (message is NotificationMessage &&
+          message.method == Method.textDocument_publishDiagnostics) {
+        diagnosticParams = message.params;
+
+        return diagnosticParams.uri == uri.toString();
+      }
+      return false;
+    });
+    return diagnosticParams.diagnostics;
+  }
+
+  /// Removes markers like `[[` and `]]` and `^` that are used for marking
+  /// positions/ranges in strings to avoid hard-coding positions in tests.
+  String withoutMarkers(String contents) =>
+      contents.replaceAll(allMarkersPattern, '');
+
+  /// Removes range markers from strings to give accurate position offsets.
+  String withoutRangeMarkers(String contents) =>
+      contents.replaceAll(rangeMarkerStart, '').replaceAll(rangeMarkerEnd, '');
+}
+
+abstract class AbstractLspAnalysisServerTest
+    with
+        ResourceProviderMixin,
+        ClientCapabilitiesHelperMixin,
+        LspAnalysisServerTestMixin {
+  MockLspServerChannel channel;
+  LspAnalysisServer server;
+
+  Stream<Message> get serverToClient => channel.serverToClient;
+
+  Future sendNotificationToServer(NotificationMessage notification) async {
+    channel.sendNotificationToServer(notification);
+    await pumpEventQueue();
+  }
+
+  Future<ResponseMessage> sendRequestToServer(RequestMessage request) {
+    return channel.sendRequestToServer(request);
+  }
+
+  void sendResponseToServer(ResponseMessage response) {
+    channel.sendResponseToServer(response);
+  }
+
   void setUp() {
     channel = new MockLspServerChannel(debugPrintCommunication);
     // Create an SDK in the mock file system.
@@ -604,33 +762,6 @@
     channel.close();
     await server.shutdown();
   }
-
-  WorkspaceFolder toWorkspaceFolder(Uri uri) {
-    return WorkspaceFolder(uri.toString(), path.basename(uri.toFilePath()));
-  }
-
-  Future<List<Diagnostic>> waitForDiagnostics(Uri uri) async {
-    PublishDiagnosticsParams diagnosticParams;
-    await channel.serverToClient.firstWhere((message) {
-      if (message is NotificationMessage &&
-          message.method == Method.textDocument_publishDiagnostics) {
-        diagnosticParams = message.params;
-
-        return diagnosticParams.uri == uri.toString();
-      }
-      return false;
-    });
-    return diagnosticParams.diagnostics;
-  }
-
-  /// Removes markers like `[[` and `]]` and `^` that are used for marking
-  /// positions/ranges in strings to avoid hard-coding positions in tests.
-  String withoutMarkers(String contents) =>
-      contents.replaceAll(allMarkersPattern, '');
-
-  /// Removes range markers from strings to give accurate position offsets.
-  String withoutRangeMarkers(String contents) =>
-      contents.replaceAll(rangeMarkerStart, '').replaceAll(rangeMarkerEnd, '');
 }
 
 mixin ClientCapabilitiesHelperMixin {
diff --git a/pkg/analysis_server/test/lsp/server_test.dart b/pkg/analysis_server/test/lsp/server_test.dart
index 233b57a..f935b60 100644
--- a/pkg/analysis_server/test/lsp/server_test.dart
+++ b/pkg/analysis_server/test/lsp/server_test.dart
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:convert';
+import 'dart:io';
+
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -37,19 +40,13 @@
 
   test_shutdown_initialized() async {
     await initialize();
-    final request = makeRequest(Method.shutdown, null);
-    final response = await channel.sendRequestToServer(request);
-    expect(response.id, equals(request.id));
-    expect(response.error, isNull);
-    expect(response.result, isNull);
+    final response = await sendShutdown();
+    expect(response, isNull);
   }
 
   test_shutdown_uninitialized() async {
-    final request = makeRequest(Method.shutdown, null);
-    final response = await channel.sendRequestToServer(request);
-    expect(response.id, equals(request.id));
-    expect(response.error, isNull);
-    expect(response.result, isNull);
+    final response = await sendShutdown();
+    expect(response, isNull);
   }
 
   test_unknownNotifications_logError() async {
@@ -68,11 +65,36 @@
     );
   }
 
+  @failingTest
+  test_diagnosticServer() async {
+    // TODO(dantup): This test fails because server.diagnosticServer is not
+    // set up in these tests. This needs moving to an integration test (which
+    // we don't yet have for LSP, but the existing server does have that we
+    // can mirror).
+    await initialize();
+
+    // Send the custom request to the LSP server to get the Dart diagnostic
+    // server info.
+    final server = await getDiagnosticServer();
+
+    expect(server.port, isNotNull);
+    expect(server.port, isNonZero);
+    expect(server.port, isPositive);
+
+    // Ensure the server was actually started.
+    final client = new HttpClient();
+    HttpClientRequest request = await client
+        .getUrl(Uri.parse('http://localhost:${server.port}/status'));
+    final response = await request.close();
+    final responseBody = await utf8.decodeStream(response);
+    expect(responseBody, contains('<title>Analysis Server</title>'));
+  }
+
   test_unknownOptionalNotifications_silentlyDropped() async {
     await initialize();
     final notification =
         makeNotification(new Method.fromJson(r'$/randomNotification'), null);
-    final firstError = channel.errorNotificationsFromServer.first;
+    final firstError = errorNotificationsFromServer.first;
     channel.sendNotificationToServer(notification);
 
     // Wait up to 1sec to ensure no error/log notifications were sent back.
diff --git a/pkg/analysis_server/test/lsp/test_all.dart b/pkg/analysis_server/test/lsp/test_all.dart
index d1e29ad..2745a6b 100644
--- a/pkg/analysis_server/test/lsp/test_all.dart
+++ b/pkg/analysis_server/test/lsp/test_all.dart
@@ -23,6 +23,7 @@
 import 'rename_test.dart' as rename_test;
 import 'server_test.dart' as server_test;
 import 'signature_help_test.dart' as signature_help_test;
+import 'folding_test.dart' as folding_test;
 
 main() {
   defineReflectiveSuite(() {
@@ -44,5 +45,6 @@
     assists_code_action_tests.main();
     packet_transformer_tests.main();
     rename_test.main();
+    folding_test.main();
   }, name: 'lsp');
 }
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index 286da86..367e52e 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart' as lsp;
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:analysis_server/lsp_protocol/protocol_special.dart' as lsp;
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/analysis_server.dart';
@@ -64,31 +65,6 @@
     return _closed.future;
   }
 
-  /**
-   * A stream of [NotificationMessage]s from the server that may be errors.
-   */
-  Stream<lsp.NotificationMessage> get errorNotificationsFromServer {
-    return notificationsFromServer.where(_isErrorNotification);
-  }
-
-  /**
-   * A stream of [NotificationMessage]s from the server.
-   */
-  Stream<lsp.NotificationMessage> get notificationsFromServer {
-    return _serverToClient.stream
-        .where((m) => m is lsp.NotificationMessage)
-        .cast<lsp.NotificationMessage>();
-  }
-
-  /**
-   * A stream of [RequestMessage]s from the server.
-   */
-  Stream<lsp.RequestMessage> get requestsFromServer {
-    return _serverToClient.stream
-        .where((m) => m is lsp.RequestMessage)
-        .cast<lsp.RequestMessage>();
-  }
-
   Stream<lsp.Message> get serverToClient => _serverToClient.stream;
 
   @override
@@ -98,6 +74,13 @@
     }
   }
 
+  /// Run the object through JSON serialisation to catch any
+  /// issues like fields that are unserialisable types. This is used for
+  /// messages going server-to-client.
+  void ensureMessageCanBeJsonSerialized(ToJsonable message) {
+    jsonEncode(message.toJson());
+  }
+
   @override
   void listen(void Function(lsp.Message message) onMessage,
       {Function onError, void Function() onDone}) {
@@ -110,6 +93,9 @@
     if (_closed.isCompleted) {
       return;
     }
+
+    ensureMessageCanBeJsonSerialized(notification);
+
     _serverToClient.add(notification);
   }
 
@@ -118,7 +104,9 @@
     if (_closed.isCompleted) {
       return;
     }
+
     notification = _convertJson(notification, lsp.NotificationMessage.fromJson);
+
     _clientToServer.add(notification);
   }
 
@@ -128,6 +116,9 @@
     if (_closed.isCompleted) {
       return;
     }
+
+    ensureMessageCanBeJsonSerialized(request);
+
     _serverToClient.add(request);
   }
 
@@ -141,7 +132,9 @@
     if (_closed.isCompleted) {
       throw new Exception('sendLspRequest after connection closed');
     }
+
     request = _convertJson(request, lsp.RequestMessage.fromJson);
+
     // Wrap send request in future to simulate WebSocket.
     new Future(() => _clientToServer.add(request));
     return waitForResponse(request);
@@ -153,6 +146,9 @@
     if (_closed.isCompleted) {
       return;
     }
+
+    ensureMessageCanBeJsonSerialized(response);
+
     // Wrap send response in future to simulate WebSocket.
     new Future(() => _serverToClient.add(response));
   }
@@ -162,7 +158,9 @@
     if (_closed.isCompleted) {
       return;
     }
+
     response = _convertJson(response, lsp.ResponseMessage.fromJson);
+
     _clientToServer.add(response);
   }
 
@@ -201,15 +199,6 @@
       lsp.ToJsonable message, T Function(Map<String, dynamic>) constructor) {
     return constructor(jsonDecode(jsonEncode(message.toJson())));
   }
-
-  /// Checks whether a notification is likely an error from the server (for
-  /// example a window/showMessage). This is useful for tests that want to
-  /// ensure no errors come from the server in response to notifications (which
-  /// don't have their own responses).
-  bool _isErrorNotification(lsp.NotificationMessage notification) {
-    return notification.method == Method.window_logMessage ||
-        notification.method == Method.window_showMessage;
-  }
 }
 
 /**
diff --git a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
index 0a1300f..1bbf623 100644
--- a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
@@ -43,8 +43,9 @@
 void main() {f^}''');
     await computeSuggestions();
 
-    assertSuggestFunction('foo', 'bool',
+    CompletionSuggestion cs = assertSuggestFunction('foo', 'bool',
         defaultArgListString: 'bar, baz: null');
+    expect(cs.elementUri, equals('package:test/b.dart'));
   }
 
   test_ArgumentList() async {
diff --git a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
index e13ad70..af3d4f8 100644
--- a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/library_member_contributor.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -26,7 +27,8 @@
     // SimpleIdentifier  PrefixedIdentifier  ExpressionStatement
     addTestSource('import "dart:async" as bar; foo() {bar.^}');
     await computeSuggestions();
-    assertSuggestClass('Future');
+    CompletionSuggestion cs = assertSuggestClass('Future');
+    expect(cs.elementUri, equals('dart:async'));
     assertNotSuggested('loadLibrary');
   }
 
diff --git a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
index 8e5f942..f38def7 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/local_library_contributor.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -42,7 +43,8 @@
     await computeSuggestions();
     expect(replacementOffset, completionOffset);
     expect(replacementLength, 0);
-    assertSuggestConstructor('A');
+    CompletionSuggestion cs = assertSuggestConstructor('A');
+    expect(cs.elementUri, 'package:test/a.dart');
     // Suggested by LocalConstructorContributor
     assertNotSuggested('B.bar');
     // Suggested by ImportedReferenceContributor
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index ffa3f3a..d484f79 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -5,6 +5,7 @@
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/local_reference_contributor.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -68,10 +69,11 @@
 void main() {h^}''');
     await computeSuggestions();
 
-    assertSuggestFunction('hasLength', 'bool',
+    CompletionSuggestion cs = assertSuggestFunction('hasLength', 'bool',
         relevance: DART_RELEVANCE_LOCAL_FUNCTION,
         defaultArgListString: 'a, b',
         defaultArgumentListTextRanges: [0, 1, 3, 1]);
+    expect(cs.elementUri, equals(convertPath('/home/test/lib/test.dart')));
   }
 
   test_ArgDefaults_function_none() async {
diff --git a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
index 49a5e34..076ae44 100644
--- a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
@@ -21,6 +21,22 @@
     return new OverrideContributor();
   }
 
+  test_alreadyOverridden() async {
+    addTestSource('''
+class A {
+  void foo() {}
+  void bar() {}
+}
+
+class B implements A {
+  void bar() {}
+  f^
+}
+''');
+    await computeSuggestions();
+    _assertNoOverrideContaining('bar');
+  }
+
   test_fromMultipleSuperclasses() async {
     addTestSource(r'''
 class A {
@@ -152,6 +168,61 @@
         selectionLength: 27);
   }
 
+  test_inClass_of_interface() async {
+    addTestSource('''
+class A {
+  void foo() {}
+}
+
+class B implements A {
+  f^
+}
+''');
+    await computeSuggestions();
+    _assertOverride('''
+@override
+  void foo() {
+    // TODO: implement foo
+  }''', displayText: 'foo() { … }', selectionOffset: 51, selectionLength: 0);
+  }
+
+  test_inMixin_of_interface() async {
+    addTestSource('''
+class A {
+  void foo() {}
+}
+
+mixin M implements A {
+  f^
+}
+''');
+    await computeSuggestions();
+    _assertOverride('''
+@override
+  void foo() {
+    // TODO: implement foo
+  }''', displayText: 'foo() { … }', selectionOffset: 51, selectionLength: 0);
+  }
+
+  test_inMixin_of_superclassConstraint() async {
+    addTestSource('''
+class A {
+  void foo() {}
+}
+
+mixin M on A {
+  f^
+}
+''');
+    await computeSuggestions();
+    _assertOverride('''
+@override
+  void foo() {
+    // TODO: implement foo
+    super.foo();
+  }''', displayText: 'foo() { … }', selectionOffset: 56, selectionLength: 12);
+  }
+
   @failingTest
   test_insideBareClass() async {
     addTestSource('''
@@ -278,6 +349,14 @@
         selectionLength: 22);
   }
 
+  void _assertNoOverrideContaining(String search) {
+    expect(
+        suggestions.where((c) =>
+            c.kind == CompletionSuggestionKind.OVERRIDE &&
+            c.completion.contains(search)),
+        isEmpty);
+  }
+
   CompletionSuggestion _assertOverride(String completion,
       {String displayText, int selectionOffset, int selectionLength}) {
     CompletionSuggestion cs = getSuggest(
diff --git a/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
index 9d1e8fb..7019111 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
@@ -204,7 +204,7 @@
     await assertHasAssist('''
 part of my_app;
 main() {
-  HashMap<String, int> /*caret*/v = getMap();
+  HashMap<String, int> v = getMap();
 }
 ''', additionallyChangedFiles: {
       appPath: [
@@ -521,14 +521,14 @@
   test_privateType_sameLibrary() async {
     await resolveTestUnit('''
 class _A {}
-_A getValue() => new _A();
+_A getValue() => _A();
 main() {
   var v = getValue();
 }
 ''');
     await assertHasAssistAt('var ', '''
 class _A {}
-_A getValue() => new _A();
+_A getValue() => _A();
 main() {
   _A v = getValue();
 }
@@ -540,7 +540,7 @@
 library my_lib;
 class A {}
 class _B extends A {}
-_B getValue() => new _B();
+_B getValue() => _B();
 ''');
     await resolveTestUnit('''
 import 'my_lib.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
index 1ff780c..cf9d0ba 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
@@ -55,7 +55,6 @@
   /// have been applied.
   Future<void> assertHasAssist(String expected,
       {Map<String, List<String>> additionallyChangedFiles}) async {
-    _setSelection();
     Assist assist = await _assertHasAssist();
     _change = assist.change;
     expect(_change.id, kind.id);
@@ -107,7 +106,6 @@
 
   /// Asserts that there is no [Assist] of the given [kind] at [_offset].
   Future<void> assertNoAssist() async {
-    _setSelection();
     List<Assist> assists = await _computeAssists();
     for (Assist assist in assists) {
       if (assist.kind == kind) {
@@ -136,6 +134,32 @@
     }).toList();
   }
 
+  @override
+  Future<void> resolveTestUnit(String code) async {
+    var offset = code.indexOf('/*caret*/');
+    if (offset >= 0) {
+      var endOffset = offset + '/*caret*/'.length;
+      code = code.substring(0, offset) + code.substring(endOffset);
+      _offset = offset;
+      _length = 0;
+    } else {
+      var startOffset = code.indexOf('// start\n');
+      var endOffset = code.indexOf('// end\n');
+      if (startOffset >= 0 && endOffset >= 0) {
+        var startLength = '// start\n'.length;
+        code = code.substring(0, startOffset) +
+            code.substring(startOffset + startLength, endOffset) +
+            code.substring(endOffset + '// end\n'.length);
+        _offset = startOffset;
+        _length = endOffset - startLength - _offset;
+      } else {
+        _offset = 0;
+        _length = 0;
+      }
+    }
+    return super.resolveTestUnit(code);
+  }
+
   /// Computes assists and verifies that there is an assist of the given kind.
   Future<Assist> _assertHasAssist() async {
     List<Assist> assists = await _computeAssists();
@@ -166,21 +190,4 @@
     }
     return positions;
   }
-
-  void _setSelection() {
-    _offset = testCode.indexOf('/*caret*/');
-    if (_offset >= 0) {
-      _offset += '/*caret*/'.length;
-      _length = 0;
-    } else {
-      _offset = testCode.indexOf('// start\n');
-      if (_offset >= 0) {
-        _offset += '// start\n'.length;
-        _length = testCode.indexOf('// end') - _offset;
-      } else {
-        _offset = 0;
-        _length = 0;
-      }
-    }
-  }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
index d76730c..79859c4 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
@@ -24,7 +24,7 @@
 const double myDouble = /*caret*/42.0;
 ''');
     await assertHasAssist('''
-const double myDouble = /*caret*/42;
+const double myDouble = 42;
 ''');
   }
 
@@ -40,7 +40,7 @@
 const double myDouble = /*caret*/4.2e1;
 ''');
     await assertHasAssist('''
-const double myDouble = /*caret*/42;
+const double myDouble = 42;
 ''');
   }
 
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
new file mode 100644
index 0000000..f4b1317
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
@@ -0,0 +1,180 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'assist_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToMultilineStringTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToMultilineStringTest extends AssistProcessorTest {
+  @override
+  AssistKind get kind => DartAssistKind.CONVERT_TO_MULTILINE_STRING;
+
+  test_doubleQuoted() async {
+    await resolveTestUnit('''
+main() {
+  print("abc");
+}
+''');
+    await assertHasAssistAt('abc', '''
+main() {
+  print("""
+abc""");
+}
+''');
+  }
+
+  test_doubleQuoted_alreadyMultiline() async {
+    await resolveTestUnit('''
+main() {
+  print("""abc""");
+}
+''');
+    await assertNoAssistAt('abc');
+  }
+
+  test_doubleQuoted_interpolation_expressionElement() async {
+    await resolveTestUnit(r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print("a $b - ${c} d");
+}
+""");
+    await assertNoAssistAt(r'c}');
+  }
+
+  test_doubleQuoted_interpolation_stringElement_begin() async {
+    await resolveTestUnit(r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print("a $b - ${c} d");
+}
+""");
+    await assertHasAssistAt('"a ', r'''
+main() {
+  var b = 'b';
+  var c = 'c';
+  print("""
+a $b - ${c} d""");
+}
+''');
+  }
+
+  test_doubleQuoted_interpolation_stringElement_middle() async {
+    await resolveTestUnit(r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print("a $b - ${c} d");
+}
+""");
+    await assertHasAssistAt('- ', r'''
+main() {
+  var b = 'b';
+  var c = 'c';
+  print("""
+a $b - ${c} d""");
+}
+''');
+  }
+
+  test_doubleQuoted_raw() async {
+    await resolveTestUnit('''
+main() {
+  print(r"abc");
+}
+''');
+    await assertHasAssistAt('abc', '''
+main() {
+  print(r"""
+abc""");
+}
+''');
+  }
+
+  test_singleQuoted() async {
+    await resolveTestUnit('''
+main() {
+  print('abc');
+}
+''');
+    await assertHasAssistAt('abc', """
+main() {
+  print('''
+abc''');
+}
+""");
+  }
+
+  test_singleQuoted_interpolation_expressionElement() async {
+    await resolveTestUnit(r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print('a $b - ${c} d');
+}
+""");
+    await assertNoAssistAt(r'c}');
+  }
+
+  test_singleQuoted_interpolation_stringElement_begin() async {
+    await resolveTestUnit(r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print('a $b - ${c} d');
+}
+""");
+    await assertHasAssistAt("'a ", r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print('''
+a $b - ${c} d''');
+}
+""");
+  }
+
+  test_singleQuoted_interpolation_stringElement_middle() async {
+    await resolveTestUnit(r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print('a $b - ${c} d');
+}
+""");
+    await assertHasAssistAt("- ", r"""
+main() {
+  var b = 'b';
+  var c = 'c';
+  print('''
+a $b - ${c} d''');
+}
+""");
+  }
+
+  test_singleQuoted_raw() async {
+    await resolveTestUnit('''
+main() {
+  print(r'abc');
+}
+''');
+    await assertHasAssistAt('abc', """
+main() {
+  print(r'''
+abc''');
+}
+""");
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
index 8d34099..00e8383 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
@@ -25,8 +25,8 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 build() {
-  return new Row(
-    /*caret*/child: new Container()
+  return Row(
+    /*caret*/child: Container()
   );
 }
 ''');
@@ -38,34 +38,30 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-// start
-    body: new Center(
-      /*caret*/child: new Container(
+  return Scaffold(
+    body: Center(
+      /*caret*/child: Container(
         width: 200.0,
         height: 300.0,
       ),
       key: null,
     ),
-// end
   );
 }
 ''');
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-// start
-    body: new Center(
-      /*caret*/children: <Widget>[
-        new Container(
+  return Scaffold(
+    body: Center(
+      children: <Widget>[
+        Container(
           width: 200.0,
           height: 300.0,
         ),
       ],
       key: null,
     ),
-// end
   );
 }
 ''');
@@ -77,35 +73,31 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-// start
-    body: new Center(
+  return Scaffold(
+    body: Center(
       /*caret*/child:
-          new Container(
+          Container(
         width: 200.0,
         height: 300.0,
       ),
       key: null,
     ),
-// end
   );
 }
 ''');
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-// start
-    body: new Center(
-      /*caret*/children: <Widget>[
-        new Container(
+  return Scaffold(
+    body: Center(
+      children: <Widget>[
+        Container(
           width: 200.0,
           height: 300.0,
         ),
       ],
       key: null,
     ),
-// end
   );
 }
 ''');
@@ -116,9 +108,9 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-    body: /*caret*/new Center(
-      child: new Container(),
+  return Scaffold(
+    body: /*caret*/Center(
+      child: Container(),
     ),
   );
 }
@@ -131,26 +123,22 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-// start
-    body: new Center(
-      /*caret*/child: new GestureDetector(),
+  return Scaffold(
+    body: Center(
+      /*caret*/child: GestureDetector(),
       key: null,
     ),
-// end
   );
 }
 ''');
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-// start
-    body: new Center(
-      /*caret*/children: <Widget>[new GestureDetector()],
+  return Scaffold(
+    body: Center(
+      children: <Widget>[GestureDetector()],
       key: null,
     ),
-// end
   );
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
index 977ea72..f4d13a4 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
@@ -27,24 +27,24 @@
 class /*caret*/MyWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
-    return new Container();
+    return Container();
   }
 }
 ''');
     await assertHasAssist(r'''
 import 'package:flutter/material.dart';
 
-class /*caret*/MyWidget extends StatefulWidget {
+class MyWidget extends StatefulWidget {
   @override
   MyWidgetState createState() {
-    return new MyWidgetState();
+    return MyWidgetState();
   }
 }
 
 class MyWidgetState extends State<MyWidget> {
   @override
   Widget build(BuildContext context) {
-    return new Container();
+    return Container();
   }
 }
 ''');
@@ -72,16 +72,16 @@
   @override
   Widget build(BuildContext context) {
     instanceField4 = instanceField1;
-    return new Row(
+    return Row(
       children: [
-        new Text(instanceField1),
-        new Text(instanceField2),
-        new Text(instanceField3),
-        new Text(instanceField4),
-        new Text(instanceField5),
-        new Text(staticField1),
-        new Text(staticField2),
-        new Text(staticField3),
+        Text(instanceField1),
+        Text(instanceField2),
+        Text(instanceField3),
+        Text(instanceField4),
+        Text(instanceField5),
+        Text(staticField1),
+        Text(staticField2),
+        Text(staticField3),
       ],
     );
   }
@@ -90,7 +90,7 @@
     await assertHasAssist(r'''
 import 'package:flutter/material.dart';
 
-class /*caret*/MyWidget extends StatefulWidget {
+class MyWidget extends StatefulWidget {
   static String staticField1;
   final String instanceField1;
   final String instanceField2;
@@ -104,7 +104,7 @@
 
   @override
   MyWidgetState createState() {
-    return new MyWidgetState();
+    return MyWidgetState();
   }
 }
 
@@ -116,16 +116,16 @@
   @override
   Widget build(BuildContext context) {
     instanceField4 = widget.instanceField1;
-    return new Row(
+    return Row(
       children: [
-        new Text(widget.instanceField1),
-        new Text(widget.instanceField2),
-        new Text(widget.instanceField3),
-        new Text(instanceField4),
-        new Text(instanceField5),
-        new Text(MyWidget.staticField1),
-        new Text(MyWidget.staticField2),
-        new Text(MyWidget.staticField3),
+        Text(widget.instanceField1),
+        Text(widget.instanceField2),
+        Text(widget.instanceField3),
+        Text(instanceField4),
+        Text(instanceField5),
+        Text(MyWidget.staticField1),
+        Text(MyWidget.staticField2),
+        Text(MyWidget.staticField3),
       ],
     );
   }
@@ -141,12 +141,12 @@
 class /*caret*/MyWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
-    return new Row(
+    return Row(
       children: [
-        new Text(staticGetter1),
-        new Text(staticGetter2),
-        new Text(instanceGetter1),
-        new Text(instanceGetter2),
+        Text(staticGetter1),
+        Text(staticGetter2),
+        Text(instanceGetter1),
+        Text(instanceGetter2),
       ],
     );
   }
@@ -163,10 +163,10 @@
     await assertHasAssist(r'''
 import 'package:flutter/material.dart';
 
-class /*caret*/MyWidget extends StatefulWidget {
+class MyWidget extends StatefulWidget {
   @override
   MyWidgetState createState() {
-    return new MyWidgetState();
+    return MyWidgetState();
   }
 
   static String get staticGetter1 => '';
@@ -177,12 +177,12 @@
 class MyWidgetState extends State<MyWidget> {
   @override
   Widget build(BuildContext context) {
-    return new Row(
+    return Row(
       children: [
-        new Text(MyWidget.staticGetter1),
-        new Text(MyWidget.staticGetter2),
-        new Text(instanceGetter1),
-        new Text(instanceGetter2),
+        Text(MyWidget.staticGetter1),
+        Text(MyWidget.staticGetter2),
+        Text(instanceGetter1),
+        Text(instanceGetter2),
       ],
     );
   }
@@ -208,11 +208,11 @@
 
   @override
   Widget build(BuildContext context) {
-    return new Row(
+    return Row(
       children: [
-        new Text(instanceField1),
-        new Text(instanceField2),
-        new Text(staticField),
+        Text(instanceField1),
+        Text(instanceField2),
+        Text(staticField),
       ],
     );
   }
@@ -239,7 +239,7 @@
     await assertHasAssist(r'''
 import 'package:flutter/material.dart';
 
-class /*caret*/MyWidget extends StatefulWidget {
+class MyWidget extends StatefulWidget {
   static String staticField;
   final String instanceField1;
 
@@ -247,7 +247,7 @@
 
   @override
   MyWidgetState createState() {
-    return new MyWidgetState();
+    return MyWidgetState();
   }
 
   static void staticMethod1() {
@@ -264,11 +264,11 @@
 
   @override
   Widget build(BuildContext context) {
-    return new Row(
+    return Row(
       children: [
-        new Text(widget.instanceField1),
-        new Text(instanceField2),
-        new Text(MyWidget.staticField),
+        Text(widget.instanceField1),
+        Text(instanceField2),
+        Text(MyWidget.staticField),
       ],
     );
   }
@@ -328,12 +328,12 @@
 
   @override
   Widget build(BuildContext context) {
-    return new Row(
+    return Row(
       children: [
-        new Text(aaa),
-        new Text(bbb),
-        new Text('$aaa'),
-        new Text('${bbb}'),
+        Text(aaa),
+        Text(bbb),
+        Text('$aaa'),
+        Text('${bbb}'),
       ],
     );
   }
@@ -342,7 +342,7 @@
     await assertHasAssist(r'''
 import 'package:flutter/material.dart';
 
-class /*caret*/MyWidget extends StatefulWidget {
+class MyWidget extends StatefulWidget {
   final String aaa;
   final String bbb;
 
@@ -350,19 +350,19 @@
 
   @override
   MyWidgetState createState() {
-    return new MyWidgetState();
+    return MyWidgetState();
   }
 }
 
 class MyWidgetState extends State<MyWidget> {
   @override
   Widget build(BuildContext context) {
-    return new Row(
+    return Row(
       children: [
-        new Text(widget.aaa),
-        new Text(widget.bbb),
-        new Text('${widget.aaa}'),
-        new Text('${widget.bbb}'),
+        Text(widget.aaa),
+        Text(widget.bbb),
+        Text('${widget.aaa}'),
+        Text('${widget.bbb}'),
       ],
     );
   }
@@ -378,24 +378,24 @@
 class /*caret*/MyWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
-    return new Container();
+    return Container();
   }
 }
 ''');
     await assertHasAssist(r'''
 import 'package:flutter/material.dart';
 
-class /*caret*/MyWidget extends StatefulWidget {
+class MyWidget extends StatefulWidget {
   @override
   MyWidgetState createState() {
-    return new MyWidgetState();
+    return MyWidgetState();
   }
 }
 
 class MyWidgetState extends State<MyWidget> {
   @override
   Widget build(BuildContext context) {
-    return new Container();
+    return Container();
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_move_down_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_move_down_test.dart
index 5885e70..27069f0 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_move_down_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_move_down_test.dart
@@ -24,11 +24,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('aaa'),
-      /*caret*/new Text('bbbbbb'),
-      new Text('ccccccccc'),
+      Text('aaa'),
+      /*caret*/Text('bbbbbb'),
+      Text('ccccccccc'),
     ],
   );
 }
@@ -36,16 +36,16 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('aaa'),
-      /*caret*/new Text('ccccccccc'),
-      new Text('bbbbbb'),
+      Text('aaa'),
+      Text('ccccccccc'),
+      Text('bbbbbb'),
     ],
   );
 }
 ''');
-    assertExitPosition(before: "new Text('bbbbbb')");
+    assertExitPosition(before: "Text('bbbbbb')");
   }
 
   test_last() async {
@@ -53,11 +53,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('aaa'),
-      new Text('bbb'),
-      /*caret*/new Text('ccc'),
+      Text('aaa'),
+      Text('bbb'),
+      /*caret*/Text('ccc'),
     ],
   );
 }
@@ -70,8 +70,8 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Center(
-    child: /*caret*/new Text('aaa'),
+  Center(
+    child: /*caret*/Text('aaa'),
   );
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_move_up_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_move_up_test.dart
index 771bb73..a6b58b6 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_move_up_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_move_up_test.dart
@@ -24,11 +24,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      /*caret*/new Text('aaa'),
-      new Text('bbb'),
-      new Text('ccc'),
+      /*caret*/Text('aaa'),
+      Text('bbb'),
+      Text('ccc'),
     ],
   );
 }
@@ -41,11 +41,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('aaa'),
-      /*caret*/new Text('bbbbbb'),
-      new Text('ccccccccc'),
+      Text('aaa'),
+      /*caret*/Text('bbbbbb'),
+      Text('ccccccccc'),
     ],
   );
 }
@@ -53,16 +53,16 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('bbbbbb'),
-      /*caret*/new Text('aaa'),
-      new Text('ccccccccc'),
+      Text('bbbbbb'),
+      Text('aaa'),
+      Text('ccccccccc'),
     ],
   );
 }
 ''');
-    assertExitPosition(before: "new Text('bbbbbb')");
+    assertExitPosition(before: "Text('bbbbbb')");
   }
 
   test_notInList() async {
@@ -70,8 +70,8 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Center(
-    child: /*caret*/new Text('aaa'),
+  Center(
+    child: /*caret*/Text('aaa'),
   );
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_remove_widget_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_remove_widget_test.dart
index 842b191..03f1287 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_remove_widget_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_remove_widget_test.dart
@@ -24,14 +24,14 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Center(
-        child: new /*caret*/Padding(
+      Center(
+        child: /*caret*/Padding(
           padding: const EdgeInsets.all(8.0),
-          child: new Center(
+          child: Center(
             heightFactor: 0.5,
-            child: new Text('foo'),
+            child: Text('foo'),
           ),
         ),
       ),
@@ -42,12 +42,12 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Center(
-        child: new Center(
+      Center(
+        child: Center(
           heightFactor: 0.5,
-          child: new Text('foo'),
+          child: Text('foo'),
         ),
       ),
     ],
@@ -61,11 +61,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Padding(
+  Padding(
     padding: const EdgeInsets.all(8.0),
-    child: new /*caret*/Center(
+    child: /*caret*/Center(
       heightFactor: 0.5,
-      child: new Text('foo'),
+      child: Text('foo'),
     ),
   );
 }
@@ -73,9 +73,9 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Padding(
+  Padding(
     padding: const EdgeInsets.all(8.0),
-    child: new Text('foo'),
+    child: Text('foo'),
   );
 }
 ''');
@@ -86,17 +86,17 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('foo'),
-      new /*caret*/Center(
+      Text('foo'),
+      /*caret*/Center(
         heightFactor: 0.5,
-        child: new Padding(
+        child: Padding(
           padding: const EdgeInsets.all(8.0),
-          child: new Text('bar'),
+          child: Text('bar'),
         ),
       ),
-      new Text('baz'),
+      Text('baz'),
     ],
   );
 }
@@ -104,14 +104,14 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('foo'),
-      new Padding(
+      Text('foo'),
+      Padding(
         padding: const EdgeInsets.all(8.0),
-        child: new Text('bar'),
+        child: Text('bar'),
       ),
-      new Text('baz'),
+      Text('baz'),
     ],
   );
 }
@@ -123,11 +123,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Center(
-    child: new /*caret*/Row(
+  Center(
+    child: /*caret*/Row(
       children: [
-        new Text('aaa'),
-        new Text('bbb'),
+        Text('aaa'),
+        Text('bbb'),
       ],
     ),
   );
@@ -141,10 +141,10 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Center(
-    child: /*caret*/new Column(
+  Center(
+    child: /*caret*/Column(
       children: [
-        new Text('foo'),
+        Text('foo'),
       ],
     ),
   );
@@ -153,8 +153,8 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Center(
-    child: /*caret*/new Text('foo'),
+  Center(
+    child: Text('foo'),
   );
 }
 ''');
@@ -165,9 +165,9 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  return /*caret*/new Column(
+  return /*caret*/Column(
     children: [
-      new Text('foo'),
+      Text('foo'),
     ],
   );
 }
@@ -175,7 +175,7 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  return /*caret*/new Text('foo');
+  return Text('foo');
 }
 ''');
   }
@@ -185,26 +185,26 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('aaa'),
-      new /*caret*/Column(
+      Text('aaa'),
+      /*caret*/Column(
         children: [
-          new Row(
+          Row(
             children: [
-              new Text('bbb'),
-              new Text('ccc'),
+              Text('bbb'),
+              Text('ccc'),
             ],
           ),
-          new Row(
+          Row(
             children: [
-              new Text('ddd'),
-              new Text('eee'),
+              Text('ddd'),
+              Text('eee'),
             ],
           ),
         ],
       ),
-      new Text('fff'),
+      Text('fff'),
     ],
   );
 }
@@ -212,22 +212,22 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: <Widget>[
-      new Text('aaa'),
-      new Row(
+      Text('aaa'),
+      Row(
         children: [
-          new Text('bbb'),
-          new Text('ccc'),
+          Text('bbb'),
+          Text('ccc'),
         ],
       ),
-      new Row(
+      Row(
         children: [
-          new Text('ddd'),
-          new Text('eee'),
+          Text('ddd'),
+          Text('eee'),
         ],
       ),
-      new Text('fff'),
+      Text('fff'),
     ],
   );
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart
index 03b6f84..7ec4246 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart
@@ -24,11 +24,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-    body: new /*caret*/GestureDetector(
+  return Scaffold(
+    body: /*caret*/GestureDetector(
       onTap: () => startResize(),
-      child: new Center(
-        child: new Container(
+      child: Center(
+        child: Container(
           width: 200.0,
           height: 300.0,
         ),
@@ -42,12 +42,12 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-    body: new Center(
+  return Scaffold(
+    body: Center(
       key: null,
-      child: new /*caret*/GestureDetector(
+      child: GestureDetector(
         onTap: () => startResize(),
-        child: new Container(
+        child: Container(
           width: 200.0,
           height: 300.0,
         ),
@@ -66,16 +66,16 @@
 
 class Foo extends StatefulWidget {
   @override
-  _State createState() => new _State();
+  _State createState() => _State();
 }
 
 class _State extends State<Foo> {
   @override
   Widget build(BuildContext context) {
-    return new /*caret*/Expanded(
+    return /*caret*/Expanded(
       flex: 2,
-      child: new GestureDetector(
-        child: new Text(
+      child: GestureDetector(
+        child: Text(
           'foo',
         ), onTap: () {
           print(42);
@@ -89,19 +89,19 @@
 
 class Foo extends StatefulWidget {
   @override
-  _State createState() => new _State();
+  _State createState() => _State();
 }
 
 class _State extends State<Foo> {
   @override
   Widget build(BuildContext context) {
-    return new GestureDetector(
+    return GestureDetector(
       onTap: () {
         print(42);
     },
-      child: new /*caret*/Expanded(
+      child: Expanded(
         flex: 2,
-        child: new Text(
+        child: Text(
           'foo',
         ),
       ),
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart
index d5ad1d3..13a88b7 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart
@@ -24,11 +24,11 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-    body: new Center(
-      child: new /*caret*/GestureDetector(
+  return Scaffold(
+    body: Center(
+      child: /*caret*/GestureDetector(
         onTap: () => startResize(),
-        child: new Container(
+        child: Container(
           width: 200.0,
           height: 300.0,
         ),
@@ -42,12 +42,12 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 build() {
-  return new Scaffold(
-    body: new /*caret*/GestureDetector(
+  return Scaffold(
+    body: GestureDetector(
       onTap: () => startResize(),
-      child: new Center(
+      child: Center(
         key: null,
-        child: new Container(
+        child: Container(
           width: 200.0,
           height: 300.0,
         ),
@@ -66,15 +66,15 @@
 
 class Foo extends StatefulWidget {
   @override
-  _State createState() => new _State();
+  _State createState() => _State();
 }
 
 class _State extends State<Foo> {
   @override
   Widget build(BuildContext context) {
-    return new GestureDetector(
-      child: new /*caret*/Expanded(
-        child: new Text(
+    return GestureDetector(
+      child: /*caret*/Expanded(
+        child: Text(
           'foo',
         ),
         flex: 2,
@@ -89,19 +89,19 @@
 
 class Foo extends StatefulWidget {
   @override
-  _State createState() => new _State();
+  _State createState() => _State();
 }
 
 class _State extends State<Foo> {
   @override
   Widget build(BuildContext context) {
-    return new /*caret*/Expanded(
+    return Expanded(
       flex: 2,
-      child: new GestureDetector(
+      child: GestureDetector(
         onTap: () {
           print(42);
       },
-        child: new Text(
+        child: Text(
           'foo',
         ),
       ),
@@ -115,14 +115,14 @@
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: [
-      new Column(
+      Column(
         children: [
-          new Padding(
-            padding: new EdgeInsets.all(16.0),
-            child: new /*caret*/Center(
-              child: new Column(
+          Padding(
+            padding: EdgeInsets.all(16.0),
+            child: /*caret*/Center(
+              child: Column(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: <Widget>[],
               ),
@@ -137,14 +137,14 @@
     await assertHasAssist('''
 import 'package:flutter/material.dart';
 main() {
-  new Column(
+  Column(
     children: [
-      new Column(
+      Column(
         children: [
-          new /*caret*/Center(
-            child: new Padding(
-              padding: new EdgeInsets.all(16.0),
-              child: new Column(
+          Center(
+            child: Padding(
+              padding: EdgeInsets.all(16.0),
+              child: Column(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: <Widget>[],
               ),
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_center_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_center_test.dart
index 4e300e2..f51ffa7 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_center_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_center_test.dart
@@ -25,7 +25,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return /*caret*/new Center();
+    return /*caret*/Center();
   }
 }
 ''');
@@ -38,7 +38,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return /*caret*/new Container();
+    return /*caret*/Container();
   }
 }
 ''');
@@ -46,7 +46,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return /*caret*/Center(child: new Container());
+    return Center(child: Container());
   }
 }
 ''');
@@ -77,7 +77,7 @@
 }
 
 main() {
-  return Center(child: MyWidget./*caret*/named());
+  return Center(child: MyWidget.named());
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
index cad4036..6e668f3 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
@@ -26,8 +26,8 @@
 
 class FakeFlutter {
   main() {
-    return new Container(
-      child: new /*caret*/Text('aaa'),
+    return Container(
+      child: /*caret*/Text('aaa'),
     );
   }
 }
@@ -37,10 +37,10 @@
 
 class FakeFlutter {
   main() {
-    return new Container(
+    return Container(
       child: Column(
         children: <Widget>[
-          new /*caret*/Text('aaa'),
+          Text('aaa'),
         ],
       ),
     );
@@ -56,13 +56,13 @@
 
 class FakeFlutter {
   main() {
-    return new Row(children: [
-      new Text('aaa'),
+    return Row(children: [
+      Text('aaa'),
 // start
-      new Text('bbb'),
-      new Text('ccc'),
+      Text('bbb'),
+      Text('ccc'),
 // end
-      new Text('ddd'),
+      Text('ddd'),
     ]);
   }
 }
@@ -72,17 +72,15 @@
 
 class FakeFlutter {
   main() {
-    return new Row(children: [
-      new Text('aaa'),
-// start
+    return Row(children: [
+      Text('aaa'),
       Column(
         children: <Widget>[
-          new Text('bbb'),
-          new Text('ccc'),
+          Text('bbb'),
+          Text('ccc'),
         ],
       ),
-// end
-      new Text('ddd'),
+      Text('ddd'),
     ]);
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_container_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_container_test.dart
index 15f8433..f52a92c 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_container_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_container_test.dart
@@ -24,7 +24,7 @@
     await resolveTestUnit('''
 import 'package:flutter/widgets.dart';
 main() {
-  return /*caret*/new Container();
+  return /*caret*/Container();
 }
 ''');
     await assertNoAssist();
@@ -35,13 +35,13 @@
     await resolveTestUnit('''
 import 'package:flutter/widgets.dart';
 main() {
-  /*caret*/new Text('a');
+  /*caret*/Text('a');
 }
 ''');
     await assertHasAssist('''
 import 'package:flutter/widgets.dart';
 main() {
-  /*caret*/Container(child: new Text('a'));
+  Container(child: Text('a'));
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
index 30b416b..40983c8 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
@@ -32,15 +32,13 @@
     await resolveTestUnit('''
 import 'package:flutter/widgets.dart';
 build() {
-  return new Container(
-    child: new Row(
-// start
+  return Container(
+    child: Row(
       children: [/*caret*/
-        new Text('111'),
-        new Text('222'),
-        new Container(),
+        Text('111'),
+        Text('222'),
+        Container(),
       ],
-// end
     ),
   );
 }
@@ -48,19 +46,17 @@
     await assertHasAssist('''
 import 'package:flutter/widgets.dart';
 build() {
-  return new Container(
-    child: new Row(
-// start
+  return Container(
+    child: Row(
       children: [
-        new widget(
-          children: [/*caret*/
-            new Text('111'),
-            new Text('222'),
-            new Container(),
+        widget(
+          children: [
+            Text('111'),
+            Text('222'),
+            Container(),
           ],
         ),
       ],
-// end
     ),
   );
 }
@@ -73,13 +69,13 @@
     await resolveTestUnit('''
 import 'package:flutter/widgets.dart';
 build() {
-  return new Container(
-    child: new Row(
+  return Container(
+    child: Row(
       children: [/*caret*/
 // start
-        new Transform(),
-        new Object(),
-        new AspectRatio(),
+        Transform(),
+        Object(),
+        AspectRatio(),
 // end
       ],
     ),
@@ -95,17 +91,15 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return new Container(
-// start
-      child: new /*caret*/DefaultTextStyle(
-        child: new Row(
+    return Container(
+      child: /*caret*/DefaultTextStyle(
+        child: Row(
           children: <Widget>[
-            new Container(
+            Container(
             ),
           ],
         ),
       ),
-// end
     );
   }
 }
@@ -114,19 +108,17 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return new Container(
-// start
+    return Container(
       child: widget(
-        child: new /*caret*/DefaultTextStyle(
-          child: new Row(
+        child: DefaultTextStyle(
+          child: Row(
             children: <Widget>[
-              new Container(
+              Container(
               ),
             ],
           ),
         ),
       ),
-// end
     );
   }
 }
@@ -139,17 +131,15 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {\r
   main() {\r
-    return new Container(\r
-// start\r
-      child: new /*caret*/DefaultTextStyle(\r
-        child: new Row(\r
+    return Container(\r
+      child: /*caret*/DefaultTextStyle(\r
+        child: Row(\r
           children: <Widget>[\r
-            new Container(\r
+            Container(\r
             ),\r
           ],\r
         ),\r
       ),\r
-// end\r
     );\r
   }\r
 }\r
@@ -158,19 +148,17 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {\r
   main() {\r
-    return new Container(\r
-// start\r
+    return Container(\r
       child: widget(\r
-        child: new /*caret*/DefaultTextStyle(\r
-          child: new Row(\r
+        child: DefaultTextStyle(\r
+          child: Row(\r
             children: <Widget>[\r
-              new Container(\r
+              Container(\r
               ),\r
             ],\r
           ),\r
         ),\r
       ),\r
-// end\r
     );\r
   }\r
 }\r
@@ -198,7 +186,7 @@
 }
 
 main(Foo foo) {
-  return widget(child: foo./*caret*/bar);
+  return widget(child: foo.bar);
 }
 ''');
   }
@@ -224,7 +212,7 @@
 }
 
 main(Foo foo) {
-  return /*caret*/widget(child: foo.bar);
+  return widget(child: foo.bar);
 }
 ''');
   }
@@ -236,9 +224,7 @@
 class FakeFlutter {
   main() {
   var obj;
-// start
-    return new Row(children: [/*caret*/ new Container()]);
-// end
+    return Row(children: [/*caret*/ Container()]);
   }
 }
 ''');
@@ -251,9 +237,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-// start
-    return /*caret*/new Container();
-// end
+    return /*caret*/Container();
   }
 }
 ''');
@@ -261,9 +245,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-// start
-    return /*caret*/widget(child: new Container());
-// end
+    return widget(child: Container());
   }
 }
 ''');
@@ -275,7 +257,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return new ClipRect./*caret*/rect();
+    return ClipRect./*caret*/rect();
   }
 }
 ''');
@@ -283,7 +265,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return widget(child: new ClipRect./*caret*/rect());
+    return widget(child: ClipRect.rect());
   }
 }
 ''');
@@ -295,7 +277,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    var container = new Container();
+    var container = Container();
     return /*caret*/container;
   }
 }
@@ -304,8 +286,8 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    var container = new Container();
-    return /*caret*/widget(child: container);
+    var container = Container();
+    return widget(child: container);
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_padding_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_padding_test.dart
index 50b927b..acc611a 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_padding_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_padding_test.dart
@@ -25,7 +25,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return /*caret*/new Container();
+    return /*caret*/Container();
   }
 }
 ''');
@@ -33,9 +33,9 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return /*caret*/Padding(
+    return Padding(
       padding: const EdgeInsets.all(8.0),
-      child: new Container(),
+      child: Container(),
     );
   }
 }
@@ -48,7 +48,7 @@
 import 'package:flutter/widgets.dart';
 class FakeFlutter {
   main() {
-    return /*caret*/new Padding();
+    return /*caret*/Padding();
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_row_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_row_test.dart
index c18ac34..32331c2 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_row_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_row_test.dart
@@ -26,13 +26,13 @@
 
 class FakeFlutter {
   main() {
-    return new Column(children: [
-      new Text('aaa'),
+    return Column(children: [
+      Text('aaa'),
 // start
-      new Text('bbb'),
-      new Text('ccc'),
+      Text('bbb'),
+      Text('ccc'),
 // end
-      new Text('ddd'),
+      Text('ddd'),
     ]);
   }
 }
@@ -42,17 +42,15 @@
 
 class FakeFlutter {
   main() {
-    return new Column(children: [
-      new Text('aaa'),
-// start
+    return Column(children: [
+      Text('aaa'),
       Row(
         children: <Widget>[
-          new Text('bbb'),
-          new Text('ccc'),
+          Text('bbb'),
+          Text('ccc'),
         ],
       ),
-// end
-      new Text('ddd'),
+      Text('ddd'),
     ]);
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_stream_builder_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_stream_builder_test.dart
index be7d5c2..c924f7e 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_stream_builder_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_stream_builder_test.dart
@@ -40,17 +40,17 @@
 import 'package:flutter/widgets.dart';
 
 main() {
-  /*caret*/new Text('a');
+  /*caret*/Text('a');
 }
 ''');
     await assertHasAssist('''
 import 'package:flutter/widgets.dart';
 
 main() {
-  /*caret*/StreamBuilder<Object>(
+  StreamBuilder<Object>(
     stream: null,
     builder: (context, snapshot) {
-      return new Text('a');
+      return Text('a');
     }
   );
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_block_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_block_test.dart
index f4647be..52f5125 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_block_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_block_test.dart
@@ -30,12 +30,10 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   {
     print(0);
     print(1);
   }
-// end
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_do_while_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_do_while_test.dart
index 96fbd14..56d81c3 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_do_while_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_do_while_test.dart
@@ -30,12 +30,10 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   do {
     print(0);
     print(1);
   } while (condition);
-// end
 }
 ''');
     assertLinkedGroup(0, ['condition);']);
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_in_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_in_test.dart
index c775e1c..6427730 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_in_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_in_test.dart
@@ -30,12 +30,10 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   for (var item in iterable) {
     print(0);
     print(1);
   }
-// end
 }
 ''');
     assertLinkedGroup(0, ['item']);
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_test.dart
index 770684c..095f0ed 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_for_test.dart
@@ -30,12 +30,10 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   for (var v = init; condition; increment) {
     print(0);
     print(1);
   }
-// end
 }
 ''');
     assertLinkedGroup(0, ['v =']);
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_if_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_if_test.dart
index de8df15..5780cfa 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_if_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_if_test.dart
@@ -30,12 +30,10 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   if (condition) {
     print(0);
     print(1);
   }
-// end
 }
 ''');
     assertLinkedGroup(0, ['condition']);
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_catch_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_catch_test.dart
index f39a5e0..bf806e9 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_catch_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_catch_test.dart
@@ -30,14 +30,12 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   try {
     print(0);
     print(1);
   } on Exception catch (e) {
     // TODO
   }
-// end
 }
 ''');
     assertLinkedGroup(0, ['Exception']);
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_finally_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_finally_test.dart
index 7e9267c..8527cd7 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_finally_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_try_finally_test.dart
@@ -30,14 +30,12 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   try {
     print(0);
     print(1);
   } finally {
     // TODO
   }
-// end
 }
 ''');
     assertLinkedGroup(0, ['// TODO']);
diff --git a/pkg/analysis_server/test/src/services/correction/assist/surround_with_while_test.dart b/pkg/analysis_server/test/src/services/correction/assist/surround_with_while_test.dart
index 939e211..38f0beb 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/surround_with_while_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/surround_with_while_test.dart
@@ -30,12 +30,10 @@
 ''');
     await assertHasAssist('''
 main() {
-// start
   while (condition) {
     print(0);
     print(1);
   }
-// end
 }
 ''');
     assertLinkedGroup(0, ['condition']);
diff --git a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
index be58fce..a090848 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
@@ -26,6 +26,7 @@
     as convert_to_double_quoted_string;
 import 'convert_to_field_parameter_test.dart' as convert_to_field_parameter;
 import 'convert_to_int_literal_test.dart' as convert_to_int_literal;
+import 'convert_to_multiline_string_test.dart' as convert_to_multiline_string;
 import 'convert_to_normal_parameter_test.dart' as convert_to_normal_parameter;
 import 'convert_to_single_quoted_string_test.dart'
     as convert_to_single_quoted_string;
@@ -88,6 +89,7 @@
     convert_to_double_quoted_string.main();
     convert_to_field_parameter.main();
     convert_to_int_literal.main();
+    convert_to_multiline_string.main();
     convert_to_normal_parameter.main();
     convert_to_single_quoted_string.main();
     encapsulate_field.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_annotation_test.dart
new file mode 100644
index 0000000..1874b6f
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_annotation_test.dart
@@ -0,0 +1,178 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(RemoveAnnotationTest);
+  });
+}
+
+@reflectiveTest
+class RemoveAnnotationTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.REMOVE_ANNOTATION;
+
+  @override
+  void setUp() {
+    super.setUp();
+    addMetaPackage();
+  }
+
+  test_factory() async {
+    await resolveTestUnit('''
+import 'package:meta/meta.dart';
+
+@factory
+f() {}
+''');
+    await assertHasFix('''
+import 'package:meta/meta.dart';
+
+f() {}
+''');
+  }
+
+  test_immutable() async {
+    await resolveTestUnit('''
+import 'package:meta/meta.dart';
+
+@immutable
+f() {}
+''');
+    await assertHasFix('''
+import 'package:meta/meta.dart';
+
+f() {}
+''');
+  }
+
+  test_literal() async {
+    await resolveTestUnit('''
+import 'package:meta/meta.dart';
+
+@literal
+f() {}
+''');
+    await assertHasFix('''
+import 'package:meta/meta.dart';
+
+f() {}
+''');
+  }
+
+  test_override_field() async {
+    await resolveTestUnit('''
+class A {
+  @override
+  String name;
+}
+''');
+    await assertHasFix('''
+class A {
+  String name;
+}
+''');
+  }
+
+  test_override_getter() async {
+    await resolveTestUnit('''
+class A {
+  @override
+  int get zero => 0;
+}
+''');
+    await assertHasFix('''
+class A {
+  int get zero => 0;
+}
+''');
+  }
+
+  test_override_method() async {
+    await resolveTestUnit('''
+class A {
+  @override
+  void m() {}
+}
+''');
+    await assertHasFix('''
+class A {
+  void m() {}
+}
+''');
+  }
+
+  test_override_setter() async {
+    await resolveTestUnit('''
+class A {
+  @override
+  set value(v) {}
+}
+''');
+    await assertHasFix('''
+class A {
+  set value(v) {}
+}
+''');
+  }
+
+  test_required_namedWithDefault() async {
+    await resolveTestUnit('''
+import 'package:meta/meta.dart';
+
+f({@required int x = 0}) {}
+''');
+    await assertHasFix('''
+import 'package:meta/meta.dart';
+
+f({int x = 0}) {}
+''');
+  }
+
+  test_required_positional() async {
+    await resolveTestUnit('''
+import 'package:meta/meta.dart';
+
+f([@required int x]) {}
+''');
+    await assertHasFix('''
+import 'package:meta/meta.dart';
+
+f([int x]) {}
+''');
+  }
+
+  test_required_required() async {
+    await resolveTestUnit('''
+import 'package:meta/meta.dart';
+
+f(@required int x) {}
+''');
+    await assertHasFix('''
+import 'package:meta/meta.dart';
+
+f(int x) {}
+''');
+  }
+
+  test_sealed() async {
+    await resolveTestUnit('''
+import 'package:meta/meta.dart';
+
+@sealed
+f() {}
+''');
+    await assertHasFix('''
+import 'package:meta/meta.dart';
+
+f() {}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart
index eec8f7c..7f2fc41 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart
@@ -19,6 +19,73 @@
   @override
   FixKind get kind => DartFixKind.REMOVE_DEAD_CODE;
 
+  test_catch_afterCatchAll_catch() async {
+    await resolveTestUnit('''
+main() {
+  try {
+  } catch (e) {
+    print('a');
+  } catch (e) {
+    print('b');
+  }
+}
+''');
+    await assertHasFix('''
+main() {
+  try {
+  } catch (e) {
+    print('a');
+  }
+}
+''');
+  }
+
+  test_catch_afterCatchAll_on() async {
+    await resolveTestUnit('''
+main() {
+  try {
+  } on Object {
+    print('a');
+  } catch (e) {
+    print('b');
+  }
+}
+''');
+    await assertHasFix('''
+main() {
+  try {
+  } on Object {
+    print('a');
+  }
+}
+''');
+  }
+
+  test_catch_subtype() async {
+    await resolveTestUnit('''
+class A {}
+class B extends A {}
+main() {
+  try {
+  } on A {
+    print('a');
+  } on B {
+    print('b');
+  }
+}
+''');
+    await assertHasFix('''
+class A {}
+class B extends A {}
+main() {
+  try {
+  } on A {
+    print('a');
+  }
+}
+''');
+  }
+
   test_condition() async {
     await resolveTestUnit('''
 main(int p) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_name_from_combinator_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_name_from_combinator_test.dart
new file mode 100644
index 0000000..3ed155e
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_name_from_combinator_test.dart
@@ -0,0 +1,357 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(RemoveNameFromCombinatorTest);
+  });
+}
+
+@reflectiveTest
+class RemoveNameFromCombinatorTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.REMOVE_NAME_FROM_COMBINATOR;
+
+  test_duplicateHiddenName_last() async {
+    await resolveTestUnit('''
+import 'dart:math' hide cos, sin, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
+  test_duplicateHiddenName_middle() async {
+    await resolveTestUnit('''
+import 'dart:math' hide cos, cos, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
+  @failingTest
+  test_duplicateHiddenName_only_last() async {
+    // It appears that the hint does not detect names that are duplicated across
+    // multiple combinators.
+    await resolveTestUnit('''
+import 'dart:math' hide cos, sin hide sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
+  @failingTest
+  test_duplicateHiddenName_only_middle() async {
+    // It appears that the hint does not detect names that are duplicated across
+    // multiple combinators.
+    await resolveTestUnit('''
+import 'dart:math' hide cos hide cos hide sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos hide sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
+  test_duplicateShownName_last() async {
+    await resolveTestUnit(
+      '''
+import 'dart:math' show cos, sin, sin;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''',
+    );
+    await assertHasFix('''
+import 'dart:math' show cos, sin;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''');
+  }
+
+  test_duplicateShownName_middle() async {
+    await resolveTestUnit('''
+import 'dart:math' show cos, cos, sin;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' show cos, sin;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''');
+  }
+
+  test_undefinedHiddenName_first() async {
+    await resolveTestUnit('''
+import 'dart:math' hide aaa, sin, tan;
+
+f(x) {
+  print(cos(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide sin, tan;
+
+f(x) {
+  print(cos(x));
+}
+''');
+  }
+
+  test_undefinedHiddenName_last() async {
+    await resolveTestUnit('''
+import 'dart:math' hide cos, sin, xxx;
+
+f(x) {
+  print(tan(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos, sin;
+
+f(x) {
+  print(tan(x));
+}
+''');
+  }
+
+  test_undefinedHiddenName_middle() async {
+    await resolveTestUnit('''
+import 'dart:math' hide cos, mmm, tan;
+
+f(x) {
+  print(sin(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos, tan;
+
+f(x) {
+  print(sin(x));
+}
+''');
+  }
+
+  test_undefinedHiddenName_only_first() async {
+    await resolveTestUnit('''
+import 'dart:math' hide aaa hide cos, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
+  test_undefinedHiddenName_only_last() async {
+    await resolveTestUnit('''
+import 'dart:math' hide cos, sin hide aaa;
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos, sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
+  test_undefinedHiddenName_only_middle() async {
+    await resolveTestUnit('''
+import 'dart:math' hide cos hide aaa hide sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' hide cos hide sin;
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
+  test_undefinedHiddenName_only_only() async {
+    await resolveTestUnit('''
+import 'dart:math' hide aaa;
+var c = sin(0.3);
+''');
+    await assertHasFix('''
+import 'dart:math';
+var c = sin(0.3);
+''');
+  }
+
+  test_undefinedHiddenName_only_only_withAs() async {
+    await resolveTestUnit('''
+import 'dart:math' as math hide aaa;
+var c = math.sin(0.3);
+''');
+    await assertHasFix('''
+import 'dart:math' as math;
+var c = math.sin(0.3);
+''');
+  }
+
+  test_undefinedShownName_first() async {
+    await resolveTestUnit('''
+import 'dart:math' show aaa, sin, tan;
+
+f(x) {
+  print(sin(x) + tan(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' show sin, tan;
+
+f(x) {
+  print(sin(x) + tan(x));
+}
+''');
+  }
+
+  test_undefinedShownName_last() async {
+    await resolveTestUnit('''
+import 'dart:math' show cos, sin, xxx;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' show cos, sin;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''');
+  }
+
+  test_undefinedShownName_middle() async {
+    await resolveTestUnit('''
+import 'dart:math' show cos, mmm, tan;
+
+f(x) {
+  print(cos(x) + tan(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' show cos, tan;
+
+f(x) {
+  print(cos(x) + tan(x));
+}
+''');
+  }
+
+  test_unusedShownName_first() async {
+    await resolveTestUnit('''
+import 'dart:math' show cos, sin, tan;
+
+f(x) {
+  print(sin(x) + tan(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' show sin, tan;
+
+f(x) {
+  print(sin(x) + tan(x));
+}
+''');
+  }
+
+  test_unusedShownName_last() async {
+    await resolveTestUnit('''
+import 'dart:math' show cos, sin, tan;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' show cos, sin;
+
+f(x) {
+  print(cos(x) + sin(x));
+}
+''');
+  }
+
+  test_unusedShownName_middle() async {
+    await resolveTestUnit('''
+import 'dart:math' show cos, sin, tan;
+
+f(x) {
+  print(cos(x) + tan(x));
+}
+''');
+    await assertHasFix('''
+import 'dart:math' show cos, tan;
+
+f(x) {
+  print(cos(x) + tan(x));
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
index 96ee02f..e7a4db9 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
@@ -86,6 +86,24 @@
 ''');
   }
 
+  test_duplicateImport() async {
+    await resolveTestUnit('''
+import 'dart:math';
+import 'dart:math';
+
+main() {
+  print(min(0, 1));
+}
+''');
+    await assertHasFix('''
+import 'dart:math';
+
+main() {
+  print(min(0, 1));
+}
+''');
+  }
+
   test_multipleOfSame_all() async {
     await resolveTestUnit('''
 import 'dart:math';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index de6f043..30cad40 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -54,6 +54,7 @@
 import 'make_field_not_final_test.dart' as make_field_not_final;
 import 'make_final_test.dart' as make_final;
 import 'move_type_arguments_to_class_test.dart' as move_type_arguments_to_class;
+import 'remove_annotation_test.dart' as remove_annotation;
 import 'remove_await_test.dart' as remove_await;
 import 'remove_dead_code_test.dart' as remove_dead_code;
 import 'remove_empty_catch_test.dart' as remove_empty_catch;
@@ -64,6 +65,7 @@
 import 'remove_initializer_test.dart' as remove_initializer;
 import 'remove_interpolation_braces_test.dart' as remove_interpolation_braces;
 import 'remove_method_declaration_test.dart' as remove_method_declaration;
+import 'remove_name_from_combinator_test.dart' as remove_name_from_combinator;
 import 'remove_parameters_in_getter_declaration_test.dart'
     as remove_parameters_in_getter_declaration;
 import 'remove_parentheses_in_getter_invocation_test.dart'
@@ -141,6 +143,7 @@
     make_field_not_final.main();
     make_final.main();
     move_type_arguments_to_class.main();
+    remove_annotation.main();
     remove_await.main();
     remove_dead_code.main();
     remove_empty_catch.main();
@@ -150,6 +153,7 @@
     remove_initializer.main();
     remove_interpolation_braces.main();
     remove_method_declaration.main();
+    remove_name_from_combinator.main();
     remove_parameters_in_getter_declaration.main();
     remove_parentheses_in_getter_invocation.main();
     remove_this_expression.main();
diff --git a/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart b/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
index abf1791..f100429 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
@@ -102,7 +102,7 @@
 
     test('parses an interface with type args', () {
       final String input = '''
-interface ResponseError<D> {
+interface MyInterface<D> {
 	data?: D;
 }
     ''';
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index fe5bf80..b696b00 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -37,8 +37,10 @@
 | telemetry/event | | | | |
 | client/registerCapability | | | | | unused, but should be used for DocumentSelector at least
 | client/unregisterCapability | | | | |
-| workspace/didChangeWatchedFiles | | | | | unused, server does own watching |
+| workspace/workspaceFolders | | | | |
 | workspace/didChangeWorkspaceFolders | ✅ | ✅ | ✅ | ✅ |
+| workspace/configuration | | | | |
+| workspace/didChangeWatchedFiles | | | | | unused, server does own watching |
 | workspace/symbol | | | | |
 | workspace/executeCommand | ✅ | ✅ | ✅ | ✅ |
 | workspace/applyEdit | ✅ | ✅ | ✅ | ✅ |
@@ -52,6 +54,7 @@
 | completionItem/resolve | | | | | not required |
 | textDocument/hover | ✅ | ✅ | ✅ | ✅ |
 | textDocument/signatureHelp | ✅ | ✅ | ✅ | ✅ | trigger character handling outstanding
+| textDocument/declaration | | | | |
 | textDocument/definition | ✅ | ✅ | ✅ | ✅ |
 | textDocument/typeDefinition | | | | |
 | textDocument/implementation | | | | |
@@ -67,10 +70,13 @@
 | codeLens/resolve | | | | |
 | textDocument/documentLink | | | | |
 | documentLink/resolve | | | | |
+| textDocument/documentColor | | | | |
+| textDocument/colorPresentation | | | | |
 | textDocument/formatting | ✅ | ✅ | ✅ | ✅ |
 | textDocument/rangeFormatting | | | | | requires support from dart_style?
 | textDocument/onTypeFormatting | ✅ | ✅ | ✅ | ✅ |
-| textDocument/rename | ✅ | ✅ | Incomplete! | |
+| textDocument/rename | ✅ | ✅ | ✅ | ✅ |
 | textDocument/prepareRename | | | | |
-| textDocument/foldingRange | | | | |
+| textDocument/foldingRange | ✅ | ✅ | ✅ | ✅ |
+
 
diff --git a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
index 6c87b90..839da75 100644
--- a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
+++ b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
@@ -24,7 +24,7 @@
   // TODO(dantup): This should return true by default, and allow opt-out for
   // those things we know are not supported. This behaviour matches the old
   // code in order to simplify diffs while migrating.
-  return name == 'ErrorCodes' || name == 'CodeActionKind';
+  return name == 'ErrorCodes' || name == 'CodeActionKind' || name == 'Method';
 }
 
 String generateDartForTypes(List<AstNode> types) {
diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
index 909a06b..23fb23f 100644
--- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart
+++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
@@ -7,6 +7,8 @@
 
 import 'package:analysis_server/src/services/correction/strings.dart';
 import 'package:http/http.dart' as http;
+
+import 'package:args/args.dart';
 import 'package:path/path.dart' as path;
 
 import 'codegen_dart.dart';
@@ -14,14 +16,40 @@
 import 'typescript.dart';
 import 'typescript_parser.dart';
 
-main() async {
+const argHelp = 'help';
+const argDownload = 'download';
+
+final argParser = new ArgParser()
+  ..addFlag(argHelp, hide: true)
+  ..addFlag(argDownload,
+      negatable: false,
+      abbr: 'd',
+      help:
+          'Download the latest version of the LSP spec before generating types');
+
+main(List<String> arguments) async {
+  final args = argParser.parse(arguments);
+  if (args[argHelp]) {
+    print(argParser.usage);
+    return;
+  }
+
   final String script = Platform.script.toFilePath();
   // 3x parent = file -> lsp_spec -> tool -> analysis_server.
   final String packageFolder = new File(script).parent.parent.parent.path;
   final String outFolder = path.join(packageFolder, 'lib', 'lsp_protocol');
   new Directory(outFolder).createSync();
 
-  final String spec = await fetchSpec();
+  await writeSpecClasses(args, outFolder);
+  await writeCustomClasses(args, outFolder);
+}
+
+Future writeSpecClasses(ArgResults args, String outFolder) async {
+  if (args[argDownload]) {
+    await downloadSpec();
+  }
+  final String spec = await readSpec();
+
   final List<AstNode> types = extractTypeScriptBlocks(spec)
       .where(shouldIncludeScriptBlock)
       .map(parseString)
@@ -39,7 +67,28 @@
   final String output = generateDartForTypes(types);
 
   new File(path.join(outFolder, 'protocol_generated.dart'))
-      .writeAsStringSync(_generatedFileHeader + output);
+      .writeAsStringSync(generatedFileHeader(2018) + output);
+}
+
+/// Writes classes used by Dart's custom LSP methods.
+Future writeCustomClasses(ArgResults args, String outFolder) async {
+  interface(String name, List<Member> fields) {
+    return new Interface(null, Token.identifier(name), [], [], fields);
+  }
+
+  field(String name, {String type, canBeNull: false, canBeUndefined: false}) {
+    return new Field(null, Token.identifier(name), Type.identifier(type),
+        canBeNull, canBeUndefined);
+  }
+
+  final List<AstNode> customTypes = [
+    interface('DartDiagnosticServer', [field('port', type: 'number')]),
+  ];
+
+  final String output = generateDartForTypes(customTypes);
+
+  new File(path.join(outFolder, 'protocol_custom_generated.dart'))
+      .writeAsStringSync(generatedFileHeader(2019) + output);
 }
 
 Namespace extractMethodsEnum(String spec) {
@@ -68,8 +117,8 @@
       comment, new Token.identifier('Method'), methodConstants);
 }
 
-const _generatedFileHeader = '''
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+String generatedFileHeader(int year) => '''
+// Copyright (c) $year, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
@@ -78,13 +127,16 @@
 // "pkg/analysis_server/tool/lsp_spec/generate_all.dart".
 
 // ignore_for_file: deprecated_member_use
+// ignore_for_file: deprecated_member_use_from_same_package
 // ignore_for_file: unnecessary_brace_in_string_interps
+// ignore_for_file: unused_import
 
 import 'dart:core' hide deprecated;
 import 'dart:core' as core show deprecated;
 import 'dart:convert' show JsonEncoder;
 import 'package:analysis_server/lsp_protocol/protocol_special.dart';
-import 'package:analysis_server/src/protocol/protocol_internal.dart' show listEqual, mapEqual;
+import 'package:analysis_server/src/protocol/protocol_internal.dart'
+    show listEqual, mapEqual;
 import 'package:analyzer/src/generated/utilities_general.dart';
 
 const jsonEncoder = const JsonEncoder.withIndent('    ');
@@ -93,6 +145,10 @@
 
 final Uri specUri = Uri.parse(
     'https://raw.githubusercontent.com/Microsoft/language-server-protocol/gh-pages/specification.md');
+final Uri specLicenseUri = Uri.parse(
+    'https://raw.githubusercontent.com/Microsoft/language-server-protocol/gh-pages/License.txt');
+final String localSpecPath = path.join(
+    path.dirname(Platform.script.toFilePath()), 'lsp_specification.md');
 
 /// Pattern to extract inline types from the `result: {xx, yy }` notes in the spec.
 /// Doesn't parse past full stops as some of these have english sentences tagged on
@@ -130,11 +186,27 @@
       .toList();
 }
 
-Future<String> fetchSpec() async {
-  final resp = await http.get(specUri);
-  return resp.body;
+Future<void> downloadSpec() async {
+  final specResp = await http.get(specUri);
+  final licenseResp = await http.get(specLicenseUri);
+  final text = [
+    '''
+This is an unmodified copy of the Language Server Protocol Specification,
+downloaded from $specUri. It is the version of the specification that was
+used to generate a portion of the Dart code used to support the protocol.
+
+To regenerate the generated code, run the script in
+"analysis_server/tool/lsp_spec/generate_all.dart" with no arguments. To
+download the latest version of the specification before regenerating the
+code, run the same script with an argument of "--download".''',
+    licenseResp.body,
+    specResp.body
+  ];
+  return new File(localSpecPath).writeAsString(text.join('\n\n---\n\n'));
 }
 
+Future<String> readSpec() => new File(localSpecPath).readAsString();
+
 /// Returns whether a script block should be parsed or not.
 bool shouldIncludeScriptBlock(String input) {
   // We can't parse literal arrays, but this script block is just an example
diff --git a/pkg/analysis_server/tool/lsp_spec/lsp_specification.md b/pkg/analysis_server/tool/lsp_spec/lsp_specification.md
new file mode 100644
index 0000000..2bb235d
--- /dev/null
+++ b/pkg/analysis_server/tool/lsp_spec/lsp_specification.md
@@ -0,0 +1,4433 @@
+This is an unmodified copy of the Language Server Protocol Specification,
+downloaded from https://raw.githubusercontent.com/Microsoft/language-server-protocol/gh-pages/specification.md. It is the version of the specification that was
+used to generate a portion of the Dart code used to support the protocol.
+
+To regenerate the generated code, run the script in
+"analysis_server/tool/lsp_spec/generate_all.dart" with no arguments. To
+download the latest version of the specification before regenerating the
+code, run the same script with an argument of "--download".
+
+
+---
+
+Copyright (c) Microsoft Corporation.
+ 
+All rights reserved. 
+
+Distributed under the following terms:
+
+1.	Documentation is licensed under the Creative Commons Attribution 3.0 United States License. Code is licensed under the MIT License.
+2. This license does not grant you rights to use any trademarks or logos of Microsoft. For Microsoft’s general trademark guidelines, go to http://go.microsoft.com/fwlink/?LinkID=254653
+
+---
+
+---
+title: Specification
+layout: specification
+sectionid: specification
+toc: true
+---
+# Language Server Protocol Specification
+
+This document describes version 3.x of the language server protocol. An implementation for node of the 3.0 version of the protocol can be found [here](https://github.com/Microsoft/vscode-languageserver-node).
+
+The 2.x version of this document can be found [here](https://github.com/Microsoft/language-server-protocol/blob/master/versions/protocol-2-x.md).
+The 1.x version of this document can be found [here](https://github.com/Microsoft/language-server-protocol/blob/master/versions/protocol-1-x.md).
+
+**Note:** edits to this specification can be made via a pull request against this markdown [document](https://github.com/Microsoft/language-server-protocol/blob/gh-pages/specification.md).
+
+## Base Protocol
+
+The base protocol consists of a header and a content part (comparable to HTTP). The header and content part are
+separated by a '\r\n'.
+
+### Header Part
+
+The header part consists of header fields. Each header field is comprised of a name and a value,
+separated by ': ' (a colon and a space).
+Each header field is terminated by '\r\n'.
+Considering the last header field and the overall header itself are each terminated with '\r\n',
+and that at least one header is mandatory, this means that two '\r\n' sequences always
+immediately precede the content part of a message.
+
+Currently the following header fields are supported:
+
+| Header Field Name | Value Type  | Description |
+|:------------------|:------------|:------------|
+| Content-Length    | number      | The length of the content part in bytes. This header is required. |
+| Content-Type      | string      | The mime type of the content part. Defaults to application/vscode-jsonrpc; charset=utf-8 |
+{: .table .table-bordered .table-responsive}
+
+The header part is encoded using the 'ascii' encoding. This includes the '\r\n' separating the header and content part.
+
+### Content Part
+
+Contains the actual content of the message. The content part of a message uses [JSON-RPC](http://www.jsonrpc.org/) to describe requests, responses and notifications. The content part is encoded using the charset provided in the Content-Type field. It defaults to `utf-8`, which is the only encoding supported right now. If a server or client receives a header with a different encoding then `utf-8` it should respond with an error.
+
+(Prior versions of the protocol used the string constant `utf8` which is not a correct encoding constant according to [specification](http://www.iana.org/assignments/character-sets/character-sets.xhtml).) For backwards compatibility it is highly recommended that a client and a server treats the string `utf8` as `utf-8`.
+
+### Example:
+
+```
+Content-Length: ...\r\n
+\r\n
+{
+	"jsonrpc": "2.0",
+	"id": 1,
+	"method": "textDocument/didOpen",
+	"params": {
+		...
+	}
+}
+```
+### Base Protocol JSON structures
+
+The following TypeScript definitions describe the base [JSON-RPC protocol](http://www.jsonrpc.org/specification):
+
+#### Abstract Message
+
+A general message as defined by JSON-RPC. The language server protocol always uses "2.0" as the `jsonrpc` version.
+
+```typescript
+interface Message {
+	jsonrpc: string;
+}
+```
+#### Request Message
+
+A request message to describe a request between the client and the server. Every processed request must send a response back to the sender of the request.
+
+```typescript
+interface RequestMessage extends Message {
+
+	/**
+	 * The request id.
+	 */
+	id: number | string;
+
+	/**
+	 * The method to be invoked.
+	 */
+	method: string;
+
+	/**
+	 * The method's params.
+	 */
+	params?: Array<any> | object;
+}
+```
+
+#### Response Message
+
+A Response Message sent as a result of a request. If a request doesn't provide a result value the receiver of a request still needs to return a response message to conform to the JSON RPC specification. The result property of the ResponseMessage should be set to `null` in this case to signal a successful request.
+
+```typescript
+interface ResponseMessage extends Message {
+	/**
+	 * The request id.
+	 */
+	id: number | string | null;
+
+	/**
+	 * The result of a request. This can be omitted in
+	 * the case of an error.
+	 */
+	result?: any;
+
+	/**
+	 * The error object in case a request fails.
+	 */
+	error?: ResponseError<any>;
+}
+
+interface ResponseError<D> {
+	/**
+	 * A number indicating the error type that occurred.
+	 */
+	code: number;
+
+	/**
+	 * A string providing a short description of the error.
+	 */
+	message: string;
+
+	/**
+	 * A Primitive or Structured value that contains additional
+	 * information about the error. Can be omitted.
+	 */
+	data?: D;
+}
+
+export namespace ErrorCodes {
+	// Defined by JSON RPC
+	export const ParseError: number = -32700;
+	export const InvalidRequest: number = -32600;
+	export const MethodNotFound: number = -32601;
+	export const InvalidParams: number = -32602;
+	export const InternalError: number = -32603;
+	export const serverErrorStart: number = -32099;
+	export const serverErrorEnd: number = -32000;
+	export const ServerNotInitialized: number = -32002;
+	export const UnknownErrorCode: number = -32001;
+
+	// Defined by the protocol.
+	export const RequestCancelled: number = -32800;
+	export const ContentModified: number = -32801;
+}
+```
+#### Notification Message
+
+A notification message. A processed notification message must not send a response back. They work like events.
+
+```typescript
+interface NotificationMessage extends Message {
+	/**
+	 * The method to be invoked.
+	 */
+	method: string;
+
+	/**
+	 * The notification's params.
+	 */
+	params?: Array<any> | object;
+}
+```
+
+#### $ Notifications and Requests
+
+Notification and requests whose methods start with '$/' are messages which are protocol implementation dependent and might not be implementable in all clients or servers. For example if the server implementation uses a single threaded synchronous programming language then there is little a server can do to react to a '$/cancelRequest' notification. If a server or client receives notifications starting with '$/' it is free to ignore the notification. If a server or client receives a requests starting with '$/' it must error the request with error code `MethodNotFound` (e.g. `-32601`).
+
+#### <a href="#cancelRequest" name="cancelRequest" class="anchor"> Cancellation Support (:arrow_right: :arrow_left:)</a>
+
+The base protocol offers support for request cancellation. To cancel a request, a notification message with the following properties is sent:
+
+_Notification_:
+* method: '$/cancelRequest'
+* params: `CancelParams` defined as follows:
+
+```typescript
+interface CancelParams {
+	/**
+	 * The request id to cancel.
+	 */
+	id: number | string;
+}
+```
+
+A request that got canceled still needs to return from the server and send a response back. It can not be left open / hanging. This is in line with the JSON RPC protocol that requires that every request sends a response back. In addition it allows for returning partial results on cancel. If the request returns an error response on cancellation it is advised to set the error code to `ErrorCodes.RequestCancelled`.
+
+## Language Server Protocol
+
+The language server protocol defines a set of JSON-RPC request, response and notification messages which are exchanged using the above base protocol. This section starts describing the basic JSON structures used in the protocol. The document uses TypeScript interfaces to describe these. Based on the basic JSON structures, the actual requests with their responses and the notifications are described.
+
+In general, the language server protocol supports JSON-RPC messages, however the base protocol defined here uses a convention such that the parameters passed to request/notification messages should be of `object` type (if passed at all). However, this does not disallow using `Array` parameter types in custom messages.
+
+The protocol currently assumes that one server serves one tool. There is currently no support in the protocol to share one server between different tools. Such a sharing would require additional protocol e.g. to lock a document to support concurrent editing.
+
+### Basic JSON Structures
+
+#### URI
+
+URI's are transferred as strings. The URI's format is defined in [http://tools.ietf.org/html/rfc3986](http://tools.ietf.org/html/rfc3986)
+
+```
+  foo://example.com:8042/over/there?name=ferret#nose
+  \_/   \______________/\_________/ \_________/ \__/
+   |           |            |            |        |
+scheme     authority       path        query   fragment
+   |   _____________________|__
+  / \ /                        \
+  urn:example:animal:ferret:nose
+```
+
+We also maintain a node module to parse a string into `scheme`, `authority`, `path`, `query`, and `fragment` URI components. The GitHub repository is [https://github.com/Microsoft/vscode-uri](https://github.com/Microsoft/vscode-uri) the npm module is [https://www.npmjs.com/package/vscode-uri](https://www.npmjs.com/package/vscode-uri).
+
+Many of the interfaces contain fields that correspond to the URI of a document. For clarity, the type of such a field is declared as a `DocumentUri`. Over the wire, it will still be transferred as a string, but this guarantees that the contents of that string can be parsed as a valid URI.
+
+```typescript
+type DocumentUri = string;
+```
+
+#### Text Documents
+
+The current protocol is tailored for textual documents whose content can be represented as a string. There is currently no support for binary documents. A position inside a document (see Position definition below) is expressed as a zero-based line and character offset. The offsets are based on a UTF-16 string representation. So a string of the form `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀` is 1 and the character offset of b is 3 since `𐐀` is represented using two code units in UTF-16. To ensure that both client and server split the string into the same line representation the protocol specifies the following end-of-line sequences: '\n', '\r\n' and '\r'.
+
+Positions are line end character agnostic. So you can not specify  a position that denotes `\r|\n` or `\n|` where `|` represents the character offset.
+
+```typescript
+export const EOL: string[] = ['\n', '\r\n', '\r'];
+```
+
+#### Position
+
+Position in a text document expressed as zero-based line and zero-based character offset. A position is between two characters like an 'insert' cursor in a editor.
+
+```typescript
+interface Position {
+	/**
+	 * Line position in a document (zero-based).
+	 */
+	line: number;
+
+	/**
+	 * Character offset on a line in a document (zero-based). Assuming that the line is
+	 * represented as a string, the `character` value represents the gap between the
+	 * `character` and `character + 1`.
+	 *
+	 * If the character value is greater than the line length it defaults back to the
+	 * line length.
+	 */
+	character: number;
+}
+```
+#### Range
+
+A range in a text document expressed as (zero-based) start and end positions. A range is comparable to a selection in an editor. Therefore the end position is exclusive. If you want to specify a range that contains a line including the line ending character(s) then use an end position denoting the start of the next line. For example:
+```typescript
+{
+    start: { line: 5, character: 23 },
+    end : { line 6, character : 0 }
+}
+```
+
+```typescript
+interface Range {
+	/**
+	 * The range's start position.
+	 */
+	start: Position;
+
+	/**
+	 * The range's end position.
+	 */
+	end: Position;
+}
+```
+
+#### Location
+
+Represents a location inside a resource, such as a line inside a text file.
+```typescript
+interface Location {
+	uri: DocumentUri;
+	range: Range;
+}
+```
+
+#### LocationLink
+
+Represents a link between a source and a target location.
+
+```typescript
+interface LocationLink {
+
+	/**
+	 * Span of the origin of this link.
+	 *
+	 * Used as the underlined span for mouse interaction. Defaults to the word range at
+	 * the mouse position.
+	 */
+	originSelectionRange?: Range;
+
+	/**
+	 * The target resource identifier of this link.
+	 */
+	targetUri: string;
+
+	/**
+	 * The full target range of this link. If the target for example is a symbol then target range is the
+	 * range enclosing this symbol not including leading/trailing whitespace but everything else
+	 * like comments. This information is typically used to highlight the range in the editor.
+	 */
+	targetRange: Range;
+
+	/**
+	 * The range that should be selected and revealed when this link is being followed, e.g the name of a function.
+	 * Must be contained by the the `targetRange`. See also `DocumentSymbol#range`
+	 */
+	targetSelectionRange: Range;
+}
+```
+
+#### Diagnostic
+
+Represents a diagnostic, such as a compiler error or warning. Diagnostic objects are only valid in the scope of a resource.
+
+```typescript
+interface Diagnostic {
+	/**
+	 * The range at which the message applies.
+	 */
+	range: Range;
+
+	/**
+	 * The diagnostic's severity. Can be omitted. If omitted it is up to the
+	 * client to interpret diagnostics as error, warning, info or hint.
+	 */
+	severity?: number;
+
+	/**
+	 * The diagnostic's code, which might appear in the user interface.
+	 */
+	code?: number | string;
+
+	/**
+	 * A human-readable string describing the source of this
+	 * diagnostic, e.g. 'typescript' or 'super lint'.
+	 */
+	source?: string;
+
+	/**
+	 * The diagnostic's message.
+	 */
+	message: string;
+
+	/**
+	 * An array of related diagnostic information, e.g. when symbol-names within
+	 * a scope collide all definitions can be marked via this property.
+	 */
+	relatedInformation?: DiagnosticRelatedInformation[];
+}
+```
+
+The protocol currently supports the following diagnostic severities:
+
+```typescript
+namespace DiagnosticSeverity {
+	/**
+	 * Reports an error.
+	 */
+	export const Error = 1;
+	/**
+	 * Reports a warning.
+	 */
+	export const Warning = 2;
+	/**
+	 * Reports an information.
+	 */
+	export const Information = 3;
+	/**
+	 * Reports a hint.
+	 */
+	export const Hint = 4;
+}
+```
+
+```typescript
+/**
+ * Represents a related message and source code location for a diagnostic. This should be
+ * used to point to code locations that cause or related to a diagnostics, e.g when duplicating
+ * a symbol in a scope.
+ */
+export interface DiagnosticRelatedInformation {
+	/**
+	 * The location of this related diagnostic information.
+	 */
+	location: Location;
+
+	/**
+	 * The message of this related diagnostic information.
+	 */
+	message: string;
+}
+```
+
+#### Command
+
+Represents a reference to a command. Provides a title which will be used to represent a command in the UI. Commands are identified by a string identifier. The recommended way to handle commands is to implement their execution on the server side if the client and server provides the corresponding capabilities. Alternatively the tool extension code could handle the command. The protocol currently doesn't specify a set of well-known commands.
+
+```typescript
+interface Command {
+	/**
+	 * Title of the command, like `save`.
+	 */
+	title: string;
+	/**
+	 * The identifier of the actual command handler.
+	 */
+	command: string;
+	/**
+	 * Arguments that the command handler should be
+	 * invoked with.
+	 */
+	arguments?: any[];
+}
+```
+
+#### TextEdit
+
+A textual edit applicable to a text document.
+
+```typescript
+interface TextEdit {
+	/**
+	 * The range of the text document to be manipulated. To insert
+	 * text into a document create a range where start === end.
+	 */
+	range: Range;
+
+	/**
+	 * The string to be inserted. For delete operations use an
+	 * empty string.
+	 */
+	newText: string;
+}
+```
+
+#### TextEdit[]
+
+Complex text manipulations are described with an array of `TextEdit`'s, representing a single change to the document.
+
+All text edits ranges refer to positions in the original document. Text edits ranges must never overlap, that means no part of the original document must be manipulated by more than one edit. However, it is possible that multiple edits have the same start position: multiple inserts, or any number of inserts followed by a single remove or replace edit. If multiple inserts have the same position, the order in the array defines the order in which the inserted strings appear in the resulting text.
+
+#### TextDocumentEdit
+
+Describes textual changes on a single text document. The text document is referred to as a `VersionedTextDocumentIdentifier` to allow clients to check the text document version before an edit is applied. A `TextDocumentEdit` describes all changes on a version Si and after they are applied move the document to version Si+1. So the creator of a `TextDocumentEdit` doesn't need to sort the array or do any kind of ordering. However the edits must be non overlapping.
+
+```typescript
+export interface TextDocumentEdit {
+	/**
+	 * The text document to change.
+	 */
+	textDocument: VersionedTextDocumentIdentifier;
+
+	/**
+	 * The edits to be applied.
+	 */
+	edits: TextEdit[];
+}
+```
+
+### File Resource changes
+
+> New in version 3.13:
+
+File resource changes allow servers to create, rename and delete files and folders via the client. Note that the names talk about files but the operations are supposed to work on files and folders. This is in line with other naming in the Language Server Protocol (see file watchers which can watch files and folders). The corresponding change literals look as follows:
+
+```typescript
+/**
+ * Options to create a file.
+ */
+export interface CreateFileOptions {
+	/**
+	 * Overwrite existing file. Overwrite wins over `ignoreIfExists`
+	 */
+	overwrite?: boolean;
+	/**
+	 * Ignore if exists.
+	 */
+	ignoreIfExists?: boolean;
+}
+
+/**
+ * Create file operation
+ */
+export interface CreateFile {
+	/**
+	 * A create
+	 */
+	kind: 'create';
+	/**
+	 * The resource to create.
+	 */
+	uri: string;
+	/**
+	 * Additional options
+	 */
+	options?: CreateFileOptions;
+}
+
+/**
+ * Rename file options
+ */
+export interface RenameFileOptions {
+	/**
+	 * Overwrite target if existing. Overwrite wins over `ignoreIfExists`
+	 */
+	overwrite?: boolean;
+	/**
+	 * Ignores if target exists.
+	 */
+	ignoreIfExists?: boolean;
+}
+
+/**
+ * Rename file operation
+ */
+export interface RenameFile {
+	/**
+	 * A rename
+	 */
+	kind: 'rename';
+	/**
+	 * The old (existing) location.
+	 */
+	oldUri: string;
+	/**
+	 * The new location.
+	 */
+	newUri: string;
+	/**
+	 * Rename options.
+	 */
+	options?: RenameFileOptions;
+}
+
+/**
+ * Delete file options
+ */
+export interface DeleteFileOptions {
+	/**
+	 * Delete the content recursively if a folder is denoted.
+	 */
+	recursive?: boolean;
+	/**
+	 * Ignore the operation if the file doesn't exist.
+	 */
+	ignoreIfNotExists?: boolean;
+}
+
+/**
+ * Delete file operation
+ */
+export interface DeleteFile {
+	/**
+	 * A delete
+	 */
+	kind: 'delete';
+	/**
+	 * The file to delete.
+	 */
+	uri: string;
+	/**
+	 * Delete options.
+	 */
+	options?: DeleteFileOptions;
+}
+```
+
+#### WorkspaceEdit
+
+A workspace edit represents changes to many resources managed in the workspace. The edit should either provide `changes` or `documentChanges`. If the client can handle versioned document edits and if `documentChange`s are present, the latter are preferred over `changes`.
+
+```typescript
+export interface WorkspaceEdit {
+	/**
+	 * Holds changes to existing resources.
+	 */
+	changes?: { [uri: string]: TextEdit[]; };
+
+	/**
+	 * Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes
+	 * are either an array of `TextDocumentEdit`s to express changes to n different text documents
+	 * where each text document edit addresses a specific version of a text document. Or it can contain
+	 * above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations.
+	 *
+	 * Whether a client supports versioned document edits is expressed via
+	 * `workspace.workspaceEdit.documentChanges` client capability.
+	 *
+	 * If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then
+	 * only plain `TextEdit`s using the `changes` property are supported.
+	 */
+	documentChanges?: (TextDocumentEdit[] | (TextDocumentEdit | CreateFile | RenameFile | DeleteFile)[]);
+}
+```
+
+#### TextDocumentIdentifier
+
+Text documents are identified using a URI. On the protocol level, URIs are passed as strings. The corresponding JSON structure looks like this:
+```typescript
+interface TextDocumentIdentifier {
+	/**
+	 * The text document's URI.
+	 */
+	uri: DocumentUri;
+}
+```
+
+#### TextDocumentItem
+
+An item to transfer a text document from the client to the server.
+
+```typescript
+interface TextDocumentItem {
+	/**
+	 * The text document's URI.
+	 */
+	uri: DocumentUri;
+
+	/**
+	 * The text document's language identifier.
+	 */
+	languageId: string;
+
+	/**
+	 * The version number of this document (it will increase after each
+	 * change, including undo/redo).
+	 */
+	version: number;
+
+	/**
+	 * The content of the opened text document.
+	 */
+	text: string;
+}
+```
+
+Text documents have a language identifier to identify a document on the server side when it handles more than one language to avoid re-interpreting the file extension. If a document refers to one of the programming languages listed below it is recommended that clients use those ids.
+
+Language | Identifier
+-------- | ----------
+Windows Bat | `bat`
+BibTeX | `bibtex`
+Clojure | `clojure`
+Coffeescript | `coffeescript`
+C | `c`
+C++ | `cpp`
+C# | `csharp`
+CSS | `css`
+Diff | `diff`
+Dart | `dart`
+Dockerfile | `dockerfile`
+F# | `fsharp`
+Git | `git-commit` and `git-rebase`
+Go | `go`
+Groovy | `groovy`
+Handlebars | `handlebars`
+HTML | `html`
+Ini | `ini`
+Java | `java`
+JavaScript | `javascript`
+JSON | `json`
+LaTeX | `latex`
+Less | `less`
+Lua | `lua`
+Makefile | `makefile`
+Markdown | `markdown`
+Objective-C | `objective-c`
+Objective-C++ | `objective-cpp`
+Perl | `perl` and `perl6`
+PHP | `php`
+Powershell | `powershell`
+Pug | `jade`
+Python | `python`
+R | `r`
+Razor (cshtml) | `razor`
+Ruby | `ruby`
+Rust | `rust`
+Sass | `scss` (syntax using curly brackets), `sass` (indented syntax)
+Scala | `scala`
+ShaderLab | `shaderlab`
+Shell Script (Bash) | `shellscript`
+SQL | `sql`
+Swift | `swift`
+TypeScript | `typescript`
+TeX | `tex`
+Visual Basic | `vb`
+XML | `xml`
+XSL | `xsl`
+YAML | `yaml`
+{: .table .table-bordered .table-responsive}
+
+#### VersionedTextDocumentIdentifier
+
+An identifier to denote a specific version of a text document.
+
+```typescript
+interface VersionedTextDocumentIdentifier extends TextDocumentIdentifier {
+	/**
+	 * The version number of this document. If a versioned text document identifier
+	 * is sent from the server to the client and the file is not open in the editor
+	 * (the server has not received an open notification before) the server can send
+	 * `null` to indicate that the version is known and the content on disk is the
+	 * truth (as speced with document content ownership).
+	 *
+	 * The version number of a document will increase after each change, including
+	 * undo/redo. The number doesn't need to be consecutive.
+	 */
+	version: number | null;
+}
+```
+
+#### TextDocumentPositionParams
+
+Was `TextDocumentPosition` in 1.0 with inlined parameters.
+
+A parameter literal used in requests to pass a text document and a position inside that document.
+
+```typescript
+interface TextDocumentPositionParams {
+	/**
+	 * The text document.
+	 */
+	textDocument: TextDocumentIdentifier;
+
+	/**
+	 * The position inside the text document.
+	 */
+	position: Position;
+}
+```
+
+#### DocumentFilter
+
+A document filter denotes a document through properties like `language`, `scheme` or `pattern`. An example is a filter that applies to TypeScript files on disk. Another example is a filter the applies to JSON files with name `package.json`:
+```typescript
+{ language: 'typescript', scheme: 'file' }
+{ language: 'json', pattern: '**/package.json' }
+```
+
+```typescript
+export interface DocumentFilter {
+	/**
+	 * A language id, like `typescript`.
+	 */
+	language?: string;
+
+	/**
+	 * A Uri [scheme](#Uri.scheme), like `file` or `untitled`.
+	 */
+	scheme?: string;
+
+	/**
+	 * A glob pattern, like `*.{ts,js}`.
+	 *
+	 * Glob patterns can have the following syntax:
+	 * - `*` to match one or more characters in a path segment
+	 * - `?` to match on one character in a path segment
+	 * - `**` to match any number of path segments, including none
+	 * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files)
+	 * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
+	 * - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
+	 */
+	pattern?: string;
+}
+```
+
+A document selector is the combination of one or more document filters.
+
+```typescript
+export type DocumentSelector = DocumentFilter[];
+```
+
+#### MarkupContent
+
+ A `MarkupContent` literal represents a string value which content can be represented in different formats. Currently `plaintext` and `markdown` are supported formats. A `MarkupContent` is usually used in documentation properties of result literals like `CompletionItem` or `SignatureInformation`.
+
+```typescript
+/**
+ * Describes the content type that a client supports in various
+ * result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
+ *
+ * Please note that `MarkupKinds` must not start with a `$`. This kinds
+ * are reserved for internal usage.
+ */
+export namespace MarkupKind {
+	/**
+	 * Plain text is supported as a content format
+	 */
+	export const PlainText: 'plaintext' = 'plaintext';
+
+	/**
+	 * Markdown is supported as a content format
+	 */
+	export const Markdown: 'markdown' = 'markdown';
+}
+export type MarkupKind = 'plaintext' | 'markdown';
+
+/**
+ * A `MarkupContent` literal represents a string value which content is interpreted base on its
+ * kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds.
+ *
+ * If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues.
+ * See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
+ *
+ * Here is an example how such a string can be constructed using JavaScript / TypeScript:
+ * ```typescript
+ * let markdown: MarkdownContent = {
+ *  kind: MarkupKind.Markdown,
+ *	value: [
+ *		'# Header',
+ *		'Some text',
+ *		'```typescript',
+ *		'someCode();',
+ *		'```'
+ *	].join('\n')
+ * };
+ * ```
+ *
+ * *Please Note* that clients might sanitize the return markdown. A client could decide to
+ * remove HTML from the markdown to avoid script execution.
+ */
+export interface MarkupContent {
+	/**
+	 * The type of the Markup
+	 */
+	kind: MarkupKind;
+
+	/**
+	 * The content itself
+	 */
+	value: string;
+}
+```
+
+### Actual Protocol
+
+This section documents the actual language server protocol. It uses the following format:
+
+* a header describing the request
+* a _Request_: section describing the format of the request sent. The method is a string identifying the request the params are documented using a TypeScript interface
+* a _Response_: section describing the format of the response. The result item describes the returned data in case of a success. The error.data describes the returned data in case of an error. Please remember that in case of a failure the response already contains an error.code and an error.message field. These fields are only spec'd if the protocol forces the use of certain error codes or messages. In cases where the server can decide on these values freely they aren't listed here.
+* a _Registration Options_ section describing the registration option if the request or notification supports dynamic capability registration.
+
+#### Request, Notification and Response ordering
+
+Responses to requests should be sent in roughly the same order as the requests appear on the server or client side. So for example if a server receives a `textDocument/completion` request and then a `textDocument/signatureHelp` request it will usually first return the response for the `textDocument/completion` and then the response for `textDocument/signatureHelp`.
+
+However, the server may decide to use a parallel execution strategy and may wish to return responses in a different order than the requests were received. The server may do so as long as this reordering doesn't affect the correctness of the responses. For example, reordering the result of `textDocument/completion` and `textDocument/signatureHelp` is allowed, as these each of these requests usually won't affect the output of the other. On the other hand, the server most likely should not reorder `textDocument/definition` and `textDocument/rename` requests, since the executing the latter may affect the result of the former.
+
+#### Server lifetime
+
+The current protocol specification defines that the lifetime of a server is managed by the client (e.g. a tool like VS Code or Emacs). It is up to the client to decide when to start (process-wise) and when to shutdown a server.
+
+#### <a href="#initialize" name="initialize" class="anchor">Initialize Request (:leftwards_arrow_with_hook:)</a>
+
+The initialize request is sent as the first request from the client to the server. If the server receives a request or notification before the `initialize` request it should act as follows:
+
+* For a request the response should be an error with `code: -32002`. The message can be picked by the server.
+* Notifications should be dropped, except for the exit notification. This will allow the exit of a server without an initialize request.
+
+Until the server has responded to the `initialize` request with an `InitializeResult`, the client must not send any additional requests or notifications to the server. In addition the server is not allowed to send any requests or notifications to the client until it has responded with an `InitializeResult`, with the exception that during the `initialize` request the server is allowed to send the notifications `window/showMessage`, `window/logMessage` and `telemetry/event` as well as the `window/showMessageRequest` request to the client.
+
+The `initialize` request may only be sent once.
+
+_Request_:
+* method: 'initialize'
+* params: `InitializeParams` defined as follows:
+
+```typescript
+interface InitializeParams {
+	/**
+	 * The process Id of the parent process that started
+	 * the server. Is null if the process has not been started by another process.
+	 * If the parent process is not alive then the server should exit (see exit notification) its process.
+	 */
+	processId: number | null;
+
+	/**
+	 * The rootPath of the workspace. Is null
+	 * if no folder is open.
+	 *
+	 * @deprecated in favour of rootUri.
+	 */
+	rootPath?: string | null;
+
+	/**
+	 * The rootUri of the workspace. Is null if no
+	 * folder is open. If both `rootPath` and `rootUri` are set
+	 * `rootUri` wins.
+	 */
+	rootUri: DocumentUri | null;
+
+	/**
+	 * User provided initialization options.
+	 */
+	initializationOptions?: any;
+
+	/**
+	 * The capabilities provided by the client (editor or tool)
+	 */
+	capabilities: ClientCapabilities;
+
+	/**
+	 * The initial trace setting. If omitted trace is disabled ('off').
+	 */
+	trace?: 'off' | 'messages' | 'verbose';
+
+	/**
+	 * The workspace folders configured in the client when the server starts.
+	 * This property is only available if the client supports workspace folders.
+	 * It can be `null` if the client supports workspace folders but none are
+	 * configured.
+	 *
+	 * Since 3.6.0
+	 */
+	workspaceFolders?: WorkspaceFolder[] | null;
+}
+```
+Where `ClientCapabilities`, `TextDocumentClientCapabilities` and `WorkspaceClientCapabilities` are defined as follows:
+
+##### `WorkspaceClientCapabilities` define capabilities the editor / tool provides on the workspace:
+
+> New in version 3.13: `ResourceOperationKind` and `FailureHandlingKind` and the client capability `workspace.workspaceEdit.resourceOperations` as well as `workspace.workspaceEdit.failureHandling`.
+
+```typescript
+
+/**
+ * The kind of resource operations supported by the client.
+ */
+export type ResourceOperationKind = 'create' | 'rename' | 'delete';
+
+export namespace ResourceOperationKind {
+
+	/**
+	 * Supports creating new files and folders.
+	 */
+	export const Create: ResourceOperationKind = 'create';
+
+	/**
+	 * Supports renaming existing files and folders.
+	 */
+	export const Rename: ResourceOperationKind = 'rename';
+
+	/**
+	 * Supports deleting existing files and folders.
+	 */
+	export const Delete: ResourceOperationKind = 'delete';
+}
+
+export type FailureHandlingKind = 'abort' | 'transactional' | 'undo' | 'textOnlyTransactional';
+
+export namespace FailureHandlingKind {
+
+	/**
+	 * Applying the workspace change is simply aborted if one of the changes provided
+	 * fails. All operations executed before the failing operation stay executed.
+	 */
+	export const Abort: FailureHandlingKind = 'abort';
+
+	/**
+	 * All operations are executed transactional. That means they either all
+	 * succeed or no changes at all are applied to the workspace.
+	 */
+	export const Transactional: FailureHandlingKind = 'transactional';
+
+
+	/**
+	 * If the workspace edit contains only textual file changes they are executed transactional.
+	 * If resource changes (create, rename or delete file) are part of the change the failure
+	 * handling strategy is abort.
+	 */
+	export const TextOnlyTransactional: FailureHandlingKind = 'textOnlyTransactional';
+
+	/**
+	 * The client tries to undo the operations already executed. But there is no
+	 * guarantee that this is succeeding.
+	 */
+	export const Undo: FailureHandlingKind = 'undo';
+}
+
+/**
+ * Workspace specific client capabilities.
+ */
+export interface WorkspaceClientCapabilities {
+	/**
+	 * The client supports applying batch edits to the workspace by supporting
+	 * the request 'workspace/applyEdit'
+	 */
+	applyEdit?: boolean;
+
+	/**
+	 * Capabilities specific to `WorkspaceEdit`s
+	 */
+	workspaceEdit?: {
+		/**
+		 * The client supports versioned document changes in `WorkspaceEdit`s
+		 */
+		documentChanges?: boolean;
+
+		/**
+		 * The resource operations the client supports. Clients should at least
+		 * support 'create', 'rename' and 'delete' files and folders.
+		 */
+		resourceOperations?: ResourceOperationKind[];
+
+		/**
+		 * The failure handling strategy of a client if applying the workspace edit
+		 * fails.
+		 */
+		failureHandling?: FailureHandlingKind;
+	};
+
+	/**
+	 * Capabilities specific to the `workspace/didChangeConfiguration` notification.
+	 */
+	didChangeConfiguration?: {
+		/**
+		 * Did change configuration notification supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
+	 */
+	didChangeWatchedFiles?: {
+		/**
+		 * Did change watched files notification supports dynamic registration. Please note
+		 * that the current protocol doesn't support static configuration for file changes
+		 * from the server side.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `workspace/symbol` request.
+	 */
+	symbol?: {
+		/**
+		 * Symbol request supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
+		 */
+		symbolKind?: {
+			/**
+			 * The symbol kind values the client supports. When this
+			 * property exists the client also guarantees that it will
+			 * handle values outside its set gracefully and falls back
+			 * to a default value when unknown.
+			 *
+			 * If this property is not present the client only supports
+			 * the symbol kinds from `File` to `Array` as defined in
+			 * the initial version of the protocol.
+			 */
+			valueSet?: SymbolKind[];
+		}
+	};
+
+	/**
+	 * Capabilities specific to the `workspace/executeCommand` request.
+	 */
+	executeCommand?: {
+		/**
+		 * Execute command supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * The client has support for workspace folders.
+	 *
+	 * Since 3.6.0
+	 */
+	workspaceFolders?: boolean;
+
+	/**
+	 * The client supports `workspace/configuration` requests.
+	 *
+	 * Since 3.6.0
+	 */
+	configuration?: boolean;
+}
+```
+
+##### `TextDocumentClientCapabilities` define capabilities the editor / tool provides on text documents.
+
+```typescript
+/**
+ * Text document specific client capabilities.
+ */
+export interface TextDocumentClientCapabilities {
+
+	synchronization?: {
+		/**
+		 * Whether text document synchronization supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports sending will save notifications.
+		 */
+		willSave?: boolean;
+
+		/**
+		 * The client supports sending a will save request and
+		 * waits for a response providing text edits which will
+		 * be applied to the document before it is saved.
+		 */
+		willSaveWaitUntil?: boolean;
+
+		/**
+		 * The client supports did save notifications.
+		 */
+		didSave?: boolean;
+	}
+
+	/**
+	 * Capabilities specific to the `textDocument/completion`
+	 */
+	completion?: {
+		/**
+		 * Whether completion supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports the following `CompletionItem` specific
+		 * capabilities.
+		 */
+		completionItem?: {
+			/**
+			 * The client supports snippets as insert text.
+			 *
+			 * A snippet can define tab stops and placeholders with `$1`, `$2`
+			 * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+			 * the end of the snippet. Placeholders with equal identifiers are linked,
+			 * that is typing in one will update others too.
+			 */
+			snippetSupport?: boolean;
+
+			/**
+			 * The client supports commit characters on a completion item.
+			 */
+			commitCharactersSupport?: boolean
+
+			/**
+			 * The client supports the following content formats for the documentation
+			 * property. The order describes the preferred format of the client.
+			 */
+			documentationFormat?: MarkupKind[];
+
+			/**
+			 * The client supports the deprecated property on a completion item.
+			 */
+			deprecatedSupport?: boolean;
+
+			/**
+			 * The client supports the preselect property on a completion item.
+			 */
+			preselectSupport?: boolean;
+		}
+
+		completionItemKind?: {
+			/**
+			 * The completion item kind values the client supports. When this
+			 * property exists the client also guarantees that it will
+			 * handle values outside its set gracefully and falls back
+			 * to a default value when unknown.
+			 *
+			 * If this property is not present the client only supports
+			 * the completion items kinds from `Text` to `Reference` as defined in
+			 * the initial version of the protocol.
+			 */
+			valueSet?: CompletionItemKind[];
+		},
+
+		/**
+		 * The client supports to send additional context information for a
+		 * `textDocument/completion` request.
+		 */
+		contextSupport?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/hover`
+	 */
+	hover?: {
+		/**
+		 * Whether hover supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports the follow content formats for the content
+		 * property. The order describes the preferred format of the client.
+		 */
+		contentFormat?: MarkupKind[];
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/signatureHelp`
+	 */
+	signatureHelp?: {
+		/**
+		 * Whether signature help supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports the following `SignatureInformation`
+		 * specific properties.
+		 */
+		signatureInformation?: {
+			/**
+			 * The client supports the follow content formats for the documentation
+			 * property. The order describes the preferred format of the client.
+			 */
+			documentationFormat?: MarkupKind[];
+
+			/**
+			 * Client capabilities specific to parameter information.
+			 */
+			parameterInformation?: {
+				/**
+				 * The client supports processing label offsets instead of a
+				 * simple label string.
+				 *
+				 * Since 3.14.0
+				 */
+				labelOffsetSupport?: boolean;
+			}
+		};
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/references`
+	 */
+	references?: {
+		/**
+		 * Whether references supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/documentHighlight`
+	 */
+	documentHighlight?: {
+		/**
+		 * Whether document highlight supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/documentSymbol`
+	 */
+	documentSymbol?: {
+		/**
+		 * Whether document symbol supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * Specific capabilities for the `SymbolKind`.
+		 */
+		symbolKind?: {
+			/**
+			 * The symbol kind values the client supports. When this
+			 * property exists the client also guarantees that it will
+			 * handle values outside its set gracefully and falls back
+			 * to a default value when unknown.
+			 *
+			 * If this property is not present the client only supports
+			 * the symbol kinds from `File` to `Array` as defined in
+			 * the initial version of the protocol.
+			 */
+			valueSet?: SymbolKind[];
+		}
+
+		/**
+		 * The client supports hierarchical document symbols.
+		 */
+		hierarchicalDocumentSymbolSupport?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/formatting`
+	 */
+	formatting?: {
+		/**
+		 * Whether formatting supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/rangeFormatting`
+	 */
+	rangeFormatting?: {
+		/**
+		 * Whether range formatting supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/onTypeFormatting`
+	 */
+	onTypeFormatting?: {
+		/**
+		 * Whether on type formatting supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+		* Capabilities specific to the `textDocument/declaration`
+		*/
+	declaration?: {
+		/**
+		 * Whether declaration supports dynamic registration. If this is set to `true`
+		 * the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+		 * return value for the corresponding server capability as well.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports additional metadata in the form of declaration links.
+		 *
+		 * Since 3.14.0
+		 */
+		linkSupport?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/definition`.
+	 *
+	 * Since 3.14.0
+	 */
+	definition?: {
+		/**
+		 * Whether definition supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports additional metadata in the form of definition links.
+		 */
+		linkSupport?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/typeDefinition`
+	 *
+	 * Since 3.6.0
+	 */
+	typeDefinition?: {
+		/**
+		 * Whether typeDefinition supports dynamic registration. If this is set to `true`
+		 * the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+		 * return value for the corresponding server capability as well.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports additional metadata in the form of definition links.
+		 *
+		 * Since 3.14.0
+		 */
+		linkSupport?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/implementation`.
+	 *
+	 * Since 3.6.0
+	 */
+	implementation?: {
+		/**
+		 * Whether implementation supports dynamic registration. If this is set to `true`
+		 * the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+		 * return value for the corresponding server capability as well.
+		 */
+		dynamicRegistration?: boolean;
+
+		/**
+		 * The client supports additional metadata in the form of definition links.
+		 *
+		 * Since 3.14.0
+		 */
+		linkSupport?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/codeAction`
+	 */
+	codeAction?: {
+		/**
+		 * Whether code action supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+		/**
+		 * The client support code action literals as a valid
+		 * response of the `textDocument/codeAction` request.
+		 *
+		 * Since 3.8.0
+		 */
+		codeActionLiteralSupport?: {
+			/**
+			 * The code action kind is support with the following value
+			 * set.
+			 */
+			codeActionKind: {
+
+				/**
+				 * The code action kind values the client supports. When this
+				 * property exists the client also guarantees that it will
+				 * handle values outside its set gracefully and falls back
+				 * to a default value when unknown.
+				 */
+				valueSet: CodeActionKind[];
+			};
+		};
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/codeLens`
+	 */
+	codeLens?: {
+		/**
+		 * Whether code lens supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/documentLink`
+	 */
+	documentLink?: {
+		/**
+		 * Whether document link supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to the `textDocument/documentColor` and the
+	 * `textDocument/colorPresentation` request.
+	 *
+	 * Since 3.6.0
+	 */
+	colorProvider?: {
+		/**
+		 * Whether colorProvider supports dynamic registration. If this is set to `true`
+		 * the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+		 * return value for the corresponding server capability as well.
+		 */
+		dynamicRegistration?: boolean;
+	}
+
+	/**
+	 * Capabilities specific to the `textDocument/rename`
+	 */
+	rename?: {
+		/**
+		 * Whether rename supports dynamic registration.
+		 */
+		dynamicRegistration?: boolean;
+		/**
+		 * The client supports testing for validity of rename operations
+		 * before execution.
+		 */
+		prepareSupport?: boolean;
+	};
+
+	/**
+	 * Capabilities specific to `textDocument/publishDiagnostics`.
+	 */
+	publishDiagnostics?: {
+		/**
+		 * Whether the clients accepts diagnostics with related information.
+		 */
+		relatedInformation?: boolean;
+	};
+	/**
+	 * Capabilities specific to `textDocument/foldingRange` requests.
+	 *
+	 * Since 3.10.0
+	 */
+	foldingRange?: {
+		/**
+		 * Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
+		 * the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+		 * return value for the corresponding server capability as well.
+		 */
+		dynamicRegistration?: boolean;
+		/**
+		 * The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
+		 * hint, servers are free to follow the limit.
+		 */
+		rangeLimit?: number;
+		/**
+		 * If set, the client signals that it only supports folding complete lines. If set, client will
+		 * ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
+		 */
+		lineFoldingOnly?: boolean;
+	};
+}
+```
+
+`ClientCapabilities` now define capabilities for dynamic registration, workspace and text document features the client supports. The `experimental` can be used to pass experimental capabilities under development. For future compatibility a `ClientCapabilities` object literal can have more properties set than currently defined. Servers receiving a `ClientCapabilities` object literal with unknown properties should ignore these properties. A missing property should be interpreted as an absence of the capability. If a missing property normally defines sub properties, all missing sub properties should be interpreted as an absence of the corresponding capability.
+
+Client capabilities got introduced with version 3.0 of the protocol. They therefore only describe capabilities that got introduced in 3.x or later. Capabilities that existed in the 2.x version of the protocol are still mandatory for clients. Clients cannot opt out of providing them. So even if a client omits the `ClientCapabilities.textDocument.synchronization` it is still required that the client provides text document synchronization (e.g. open, changed and close notifications).
+
+```typescript
+interface ClientCapabilities {
+	/**
+	 * Workspace specific client capabilities.
+	 */
+	workspace?: WorkspaceClientCapabilities;
+
+	/**
+	 * Text document specific client capabilities.
+	 */
+	textDocument?: TextDocumentClientCapabilities;
+
+	/**
+	 * Experimental client capabilities.
+	 */
+	experimental?: any;
+}
+```
+
+_Response_:
+* result: `InitializeResult` defined as follows:
+
+```typescript
+interface InitializeResult {
+	/**
+	 * The capabilities the language server provides.
+	 */
+	capabilities: ServerCapabilities;
+}
+```
+* error.code:
+
+```typescript
+/**
+ * Known error codes for an `InitializeError`;
+ */
+export namespace InitializeError {
+	/**
+	 * If the protocol version provided by the client can't be handled by the server.
+	 * @deprecated This initialize error got replaced by client capabilities. There is
+	 * no version handshake in version 3.0x
+	 */
+	export const unknownProtocolVersion: number = 1;
+}
+```
+
+* error.data:
+
+```typescript
+interface InitializeError {
+	/**
+	 * Indicates whether the client execute the following retry logic:
+	 * (1) show the message provided by the ResponseError to the user
+	 * (2) user selects retry or cancel
+	 * (3) if user selected retry the initialize method is sent again.
+	 */
+	retry: boolean;
+}
+```
+
+The server can signal the following capabilities:
+
+```typescript
+/**
+ * Defines how the host (editor) should sync document changes to the language server.
+ */
+export namespace TextDocumentSyncKind {
+	/**
+	 * Documents should not be synced at all.
+	 */
+	export const None = 0;
+
+	/**
+	 * Documents are synced by always sending the full content
+	 * of the document.
+	 */
+	export const Full = 1;
+
+	/**
+	 * Documents are synced by sending the full content on open.
+	 * After that only incremental updates to the document are
+	 * send.
+	 */
+	export const Incremental = 2;
+}
+
+/**
+ * Completion options.
+ */
+export interface CompletionOptions {
+	/**
+	 * The server provides support to resolve additional
+	 * information for a completion item.
+	 */
+	resolveProvider?: boolean;
+
+	/**
+	 * The characters that trigger completion automatically.
+	 */
+	triggerCharacters?: string[];
+}
+/**
+ * Signature help options.
+ */
+export interface SignatureHelpOptions {
+	/**
+	 * The characters that trigger signature help
+	 * automatically.
+	 */
+	triggerCharacters?: string[];
+}
+
+/**
+ * Code Action options.
+ */
+export interface CodeActionOptions {
+	/**
+	 * CodeActionKinds that this server may return.
+	 *
+	 * The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
+	 * may list out every specific kind they provide.
+	 */
+	codeActionKinds?: CodeActionKind[];
+}
+
+/**
+ * Code Lens options.
+ */
+export interface CodeLensOptions {
+	/**
+	 * Code lens has a resolve provider as well.
+	 */
+	resolveProvider?: boolean;
+}
+
+/**
+ * Format document on type options.
+ */
+export interface DocumentOnTypeFormattingOptions {
+	/**
+	 * A character on which formatting should be triggered, like `}`.
+	 */
+	firstTriggerCharacter: string;
+
+	/**
+	 * More trigger characters.
+	 */
+	moreTriggerCharacter?: string[];
+}
+
+/**
+ * Rename options
+ */
+export interface RenameOptions {
+	/**
+	 * Renames should be checked and tested before being executed.
+	 */
+	prepareProvider?: boolean;
+}
+
+/**
+ * Document link options.
+ */
+export interface DocumentLinkOptions {
+	/**
+	 * Document links have a resolve provider as well.
+	 */
+	resolveProvider?: boolean;
+}
+
+/**
+ * Execute command options.
+ */
+export interface ExecuteCommandOptions {
+	/**
+	 * The commands to be executed on the server
+	 */
+	commands: string[]
+}
+
+/**
+ * Save options.
+ */
+export interface SaveOptions {
+	/**
+	 * The client is supposed to include the content on save.
+	 */
+	includeText?: boolean;
+}
+
+/**
+ * Color provider options.
+ */
+export interface ColorProviderOptions {
+}
+
+/**
+ * Folding range provider options.
+ */
+export interface FoldingRangeProviderOptions {
+}
+
+export interface TextDocumentSyncOptions {
+	/**
+	 * Open and close notifications are sent to the server.
+	 */
+	openClose?: boolean;
+	/**
+	 * Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full
+	 * and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None.
+	 */
+	change?: number;
+	/**
+	 * Will save notifications are sent to the server.
+	 */
+	willSave?: boolean;
+	/**
+	 * Will save wait until requests are sent to the server.
+	 */
+	willSaveWaitUntil?: boolean;
+	/**
+	 * Save notifications are sent to the server.
+	 */
+	save?: SaveOptions;
+}
+
+/**
+ * Static registration options to be returned in the initialize request.
+ */
+interface StaticRegistrationOptions {
+	/**
+	 * The id used to register the request. The id can be used to deregister
+	 * the request again. See also Registration#id.
+	 */
+	id?: string;
+}
+
+interface ServerCapabilities {
+	/**
+	 * Defines how text documents are synced. Is either a detailed structure defining each notification or
+	 * for backwards compatibility the TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`.
+	 */
+	textDocumentSync?: TextDocumentSyncOptions | number;
+	/**
+	 * The server provides hover support.
+	 */
+	hoverProvider?: boolean;
+	/**
+	 * The server provides completion support.
+	 */
+	completionProvider?: CompletionOptions;
+	/**
+	 * The server provides signature help support.
+	 */
+	signatureHelpProvider?: SignatureHelpOptions;
+	/**
+	 * The server provides goto definition support.
+	 */
+	definitionProvider?: boolean;
+	/**
+	 * The server provides Goto Type Definition support.
+	 *
+	 * Since 3.6.0
+	 */
+	typeDefinitionProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
+	/**
+	 * The server provides Goto Implementation support.
+	 *
+	 * Since 3.6.0
+	 */
+	implementationProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
+	/**
+	 * The server provides find references support.
+	 */
+	referencesProvider?: boolean;
+	/**
+	 * The server provides document highlight support.
+	 */
+	documentHighlightProvider?: boolean;
+	/**
+	 * The server provides document symbol support.
+	 */
+	documentSymbolProvider?: boolean;
+	/**
+	 * The server provides workspace symbol support.
+	 */
+	workspaceSymbolProvider?: boolean;
+	/**
+	 * The server provides code actions. The `CodeActionOptions` return type is only
+	 * valid if the client signals code action literal support via the property
+	 * `textDocument.codeAction.codeActionLiteralSupport`.
+	 */
+	codeActionProvider?: boolean | CodeActionOptions;
+	/**
+	 * The server provides code lens.
+	 */
+	codeLensProvider?: CodeLensOptions;
+	/**
+	 * The server provides document formatting.
+	 */
+	documentFormattingProvider?: boolean;
+	/**
+	 * The server provides document range formatting.
+	 */
+	documentRangeFormattingProvider?: boolean;
+	/**
+	 * The server provides document formatting on typing.
+	 */
+	documentOnTypeFormattingProvider?: DocumentOnTypeFormattingOptions;
+	/**
+	 * The server provides rename support. RenameOptions may only be
+	 * specified if the client states that it supports
+	 * `prepareSupport` in its initial `initialize` request.
+	 */
+	renameProvider?: boolean | RenameOptions;
+	/**
+	 * The server provides document link support.
+	 */
+	documentLinkProvider?: DocumentLinkOptions;
+	/**
+	 * The server provides color provider support.
+	 *
+	 * Since 3.6.0
+	 */
+	colorProvider?: boolean | ColorProviderOptions | (ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions);
+	/**
+	 * The server provides folding provider support.
+	 *
+	 * Since 3.10.0
+	 */
+	foldingRangeProvider?: boolean | FoldingRangeProviderOptions | (FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions);
+	/**
+	 * The server provides execute command support.
+	 */
+	executeCommandProvider?: ExecuteCommandOptions;
+	/**
+	 * Workspace specific server capabilities
+	 */
+	workspace?: {
+		/**
+		 * The server supports workspace folder.
+		 *
+		 * Since 3.6.0
+		 */
+		workspaceFolders?: {
+			/**
+			* The server has support for workspace folders
+			*/
+			supported?: boolean;
+			/**
+			* Whether the server wants to receive workspace folder
+			* change notifications.
+			*
+			* If a strings is provided the string is treated as a ID
+			* under which the notification is registered on the client
+			* side. The ID can be used to unregister for these events
+			* using the `client/unregisterCapability` request.
+			*/
+			changeNotifications?: string | boolean;
+		}
+	}
+	/**
+	 * Experimental server capabilities.
+	 */
+	experimental?: any;
+}
+```
+
+#### <a href="#initialized" name="initialized" class="anchor">Initialized Notification (:arrow_right:)</a>
+
+The initialized notification is sent from the client to the server after the client received the result of the `initialize` request but before the client is sending any other request or notification to the server. The server can use the `initialized` notification for example to dynamically register capabilities. The `initialized` notification may only be sent once.
+
+_Notification_:
+* method: 'initialized'
+* params: `InitializedParams` defined as follows:
+
+```typescript
+interface InitializedParams {
+}
+```
+
+#### <a href="#shutdown" name="shutdown" class="anchor">Shutdown Request (:leftwards_arrow_with_hook:)</a>
+
+The shutdown request is sent from the client to the server. It asks the server to shut down, but to not exit (otherwise the response might not be delivered correctly to the client). There is a separate exit notification that asks the server to exit.
+
+_Request_:
+* method: 'shutdown'
+* params: void
+
+_Response_:
+* result: null
+* error: code and message set in case an exception happens during shutdown request.
+
+#### <a href="#exit" name="exit" class="anchor">Exit Notification (:arrow_right:)</a>
+
+A notification to ask the server to exit its process.
+The server should exit with `success` code 0 if the shutdown request has been received before; otherwise with `error` code 1.
+
+_Notification_:
+* method: 'exit'
+* params: void
+
+#### <a href="#window_showMessage" name="window_showMessage" class="anchor">ShowMessage Notification (:arrow_left:)</a>
+
+The show message notification is sent from a server to a client to ask the client to display a particular message in the user interface.
+
+_Notification_:
+* method: 'window/showMessage'
+* params: `ShowMessageParams` defined as follows:
+
+```typescript
+interface ShowMessageParams {
+	/**
+	 * The message type. See {@link MessageType}.
+	 */
+	type: number;
+
+	/**
+	 * The actual message.
+	 */
+	message: string;
+}
+```
+
+Where the type is defined as follows:
+
+```typescript
+export namespace MessageType {
+	/**
+	 * An error message.
+	 */
+	export const Error = 1;
+	/**
+	 * A warning message.
+	 */
+	export const Warning = 2;
+	/**
+	 * An information message.
+	 */
+	export const Info = 3;
+	/**
+	 * A log message.
+	 */
+	export const Log = 4;
+}
+```
+
+#### <a href="#window_showMessageRequest" name="window_showMessageRequest" class="anchor">ShowMessage Request (:arrow_right_hook:)</a>
+
+The show message request is sent from a server to a client to ask the client to display a particular message in the user interface. In addition to the show message notification the request allows to pass actions and to wait for an answer from the client.
+
+_Request_:
+* method: 'window/showMessageRequest'
+* params: `ShowMessageRequestParams` defined as follows:
+
+_Response_:
+* result: the selected `MessageActionItem` \| `null` if none got selected.
+* error: code and message set in case an exception happens during showing a message.
+
+```typescript
+interface ShowMessageRequestParams {
+	/**
+	 * The message type. See {@link MessageType}
+	 */
+	type: number;
+
+	/**
+	 * The actual message
+	 */
+	message: string;
+
+	/**
+	 * The message action items to present.
+	 */
+	actions?: MessageActionItem[];
+}
+```
+
+Where the `MessageActionItem` is defined as follows:
+
+```typescript
+interface MessageActionItem {
+	/**
+	 * A short title like 'Retry', 'Open Log' etc.
+	 */
+	title: string;
+}
+```
+
+#### <a href="#window_logMessage" name="window_logMessage" class="anchor">LogMessage Notification (:arrow_left:)</a>
+
+The log message notification is sent from the server to the client to ask the client to log a particular message.
+
+_Notification_:
+* method: 'window/logMessage'
+* params: `LogMessageParams` defined as follows:
+
+```typescript
+interface LogMessageParams {
+	/**
+	 * The message type. See {@link MessageType}
+	 */
+	type: number;
+
+	/**
+	 * The actual message
+	 */
+	message: string;
+}
+```
+
+Where type is defined as above.
+
+#### <a href="#telemetry_event" name="telemetry_event" class="anchor">Telemetry Notification (:arrow_left:)</a>
+
+The telemetry notification is sent from the server to the client to ask the client to log a telemetry event.
+
+_Notification_:
+* method: 'telemetry/event'
+* params: 'any'
+
+#### <a href="#client_registerCapability" name="client_registerCapability" class="anchor">Register Capability (:arrow_right_hook:)</a>
+
+The `client/registerCapability` request is sent from the server to the client to register for a new capability on the client side. Not all clients need to support dynamic capability registration. A client opts in via the `dynamicRegistration` property on the specific client capabilities. A client can even provide dynamic registration for capability A but not for capability B (see `TextDocumentClientCapabilities` as an example).
+
+_Request_:
+* method: 'client/registerCapability'
+* params: `RegistrationParams`
+
+Where `RegistrationParams` are defined as follows:
+
+```typescript
+/**
+ * General parameters to register for a capability.
+ */
+export interface Registration {
+	/**
+	 * The id used to register the request. The id can be used to deregister
+	 * the request again.
+	 */
+	id: string;
+
+	/**
+	 * The method / capability to register for.
+	 */
+	method: string;
+
+	/**
+	 * Options necessary for the registration.
+	 */
+	registerOptions?: any;
+}
+
+export interface RegistrationParams {
+	registrations: Registration[];
+}
+```
+
+Since most of the registration options require to specify a document selector there is a base interface that can be used.
+
+```typescript
+export interface TextDocumentRegistrationOptions {
+	/**
+	 * A document selector to identify the scope of the registration. If set to null
+	 * the document selector provided on the client side will be used.
+	 */
+	documentSelector: DocumentSelector | null;
+}
+```
+
+An example JSON RPC message to register dynamically for the `textDocument/willSaveWaitUntil` feature on the client side is as follows (only details shown):
+
+```json
+{
+	"method": "client/registerCapability",
+	"params": {
+		"registrations": [
+			{
+				"id": "79eee87c-c409-4664-8102-e03263673f6f",
+				"method": "textDocument/willSaveWaitUntil",
+				"registerOptions": {
+					"documentSelector": [
+						{ "language": "javascript" }
+					]
+				}
+			}
+		]
+	}
+}
+```
+
+This message is sent from the server to the client and after the client has successfully executed the request further `textDocument/willSaveWaitUntil` requests for JavaScript text documents are sent from the client to the server.
+
+_Response_:
+* result: void.
+* error: code and message set in case an exception happens during the request.
+
+#### <a href="#client_unregisterCapability" name="client_unregisterCapability" class="anchor">Unregister Capability (:arrow_right_hook:)</a>
+
+The `client/unregisterCapability` request is sent from the server to the client to unregister a previously registered capability.
+
+_Request_:
+* method: 'client/unregisterCapability'
+* params: `UnregistrationParams`
+
+Where `UnregistrationParams` are defined as follows:
+
+```typescript
+/**
+ * General parameters to unregister a capability.
+ */
+export interface Unregistration {
+	/**
+	 * The id used to unregister the request or notification. Usually an id
+	 * provided during the register request.
+	 */
+	id: string;
+
+	/**
+	 * The method / capability to unregister for.
+	 */
+	method: string;
+}
+
+export interface UnregistrationParams {
+	unregisterations: Unregistration[];
+}
+```
+
+An example JSON RPC message to unregister the above registered `textDocument/willSaveWaitUntil` feature looks like this:
+
+```json
+{
+	"method": "client/unregisterCapability",
+	"params": {
+		"unregisterations": [
+			{
+				"id": "79eee87c-c409-4664-8102-e03263673f6f",
+				"method": "textDocument/willSaveWaitUntil"
+			}
+		]
+	}
+}
+```
+_Response_:
+* result: void.
+* error: code and message set in case an exception happens during the request.
+
+##### <a href="#workspace_workspaceFolders" name="workspace_workspaceFolders" class="anchor">Workspace folders request (:arrow_right_hook:)</a>
+
+> *Since version 3.6.0*
+
+Many tools support more than one root folder per workspace. Examples for this are VS Code's multi-root support, Atom's project folder support or Sublime's project support. If a client workspace consists of multiple roots then a server typically needs to know about this. The protocol up to now assumes one root folder which is announced to the server by the `rootUri` property of the `InitializeParams`. If the client supports workspace folders and announces them via the corresponding `workspaceFolders` client capability, the `InitializeParams` contain an additional property `workspaceFolders` with the configured workspace folders when the server starts.
+
+The `workspace/workspaceFolders` request is sent from the server to the client to fetch the current open list of workspace folders. Returns `null` in the response if only a single file is open in the tool. Returns an empty array if a workspace is open but no folders are configured.
+
+_Request_:
+
+* method: 'workspace/workspaceFolders'
+* params: none
+
+_Response_:
+
+* result: `WorkspaceFolder[] | null` defined as follows:
+
+```typescript
+export interface WorkspaceFolder {
+	/**
+	 * The associated URI for this workspace folder.
+	 */
+	uri: string;
+
+	/**
+	 * The name of the workspace folder. Defaults to the
+	 * uri's basename.
+	 */
+	name: string;
+}
+```
+* error: code and message set in case an exception happens during the 'workspace/workspaceFolders' request
+
+##### <a href="#workspace_didChangeWorkspaceFolders" name="workspace_didChangeWorkspaceFolders" class="anchor">DidChangeWorkspaceFolders Notification (:arrow_right:)</a>
+
+> *Since version 3.6.0*
+
+The `workspace/didChangeWorkspaceFolders` notification is sent from the client to the server to inform the server about workspace folder configuration changes. The notification is sent by default if both _ServerCapabilities/workspace/workspaceFolders_ and _ClientCapabilities/workspace/workspaceFolders_ are true; or if the server has registered itself to receive this notification. To register for the `workspace/didChangeWorkspaceFolders` send a `client/registerCapability` request from the server to the client. The registration parameter must have a `registrations` item of the following form, where `id` is a unique id used to unregister the capability (the example uses a UUID):
+```ts
+{
+	id: "28c6150c-bd7b-11e7-abc4-cec278b6b50a",
+	method: "workspace/didChangeWorkspaceFolders"
+}
+```
+
+_Notification_:
+
+* method: 'workspace/didChangeWorkspaceFolders'
+* params: `DidChangeWorkspaceFoldersParams` defined as follows:
+
+```typescript
+export interface DidChangeWorkspaceFoldersParams {
+	/**
+	 * The actual workspace folder change event.
+	 */
+	event: WorkspaceFoldersChangeEvent;
+}
+
+/**
+ * The workspace folder change event.
+ */
+export interface WorkspaceFoldersChangeEvent {
+	/**
+	 * The array of added workspace folders
+	 */
+	added: WorkspaceFolder[];
+
+	/**
+	 * The array of the removed workspace folders
+	 */
+	removed: WorkspaceFolder[];
+}
+```
+
+#### <a href="#workspace_didChangeConfiguration" name="workspace_didChangeConfiguration" class="anchor">DidChangeConfiguration Notification (:arrow_right:)</a>
+
+A notification sent from the client to the server to signal the change of configuration settings.
+
+_Notification_:
+* method: 'workspace/didChangeConfiguration',
+* params: `DidChangeConfigurationParams` defined as follows:
+
+```typescript
+interface DidChangeConfigurationParams {
+	/**
+	 * The actual changed settings
+	 */
+	settings: any;
+}
+```
+
+#### <a href="#workspace_configuration" name="workspace_configuration" class="anchor">Configuration Request (:arrow_right_hook:)</a>
+
+> *Since version 3.6.0*
+
+The `workspace/configuration` request is sent from the server to the client to fetch configuration settings from the client. The request can fetch several configuration settings in one roundtrip. The order of the returned configuration settings correspond to the order of the passed `ConfigurationItems` (e.g. the first item in the response is the result for the first configuration item in the params).
+
+A `ConfigurationItem` consists of the configuration section to ask for and an additional scope URI. The configuration section ask for is defined by the server and doesn't necessarily need to correspond to the configuration store used be the client. So a server might ask for a configuration `cpp.formatterOptions` but the client stores the configuration in a XML store layout differently. It is up to the client to do the necessary conversion. If a scope URI is provided the client should return the setting scoped to the provided resource. If the client for example uses [EditorConfig](http://editorconfig.org/) to manage its settings the configuration should be returned for the passed resource URI. If the client can't provide a configuration setting for a given scope then `null` need to be present in the returned array.
+
+_Request_:
+
+* method: 'workspace/configuration'
+* params: `ConfigurationParams` defined as follows
+
+```typescript
+export interface ConfigurationParams {
+	items: ConfigurationItem[];
+}
+
+export interface ConfigurationItem {
+	/**
+	 * The scope to get the configuration section for.
+	 */
+	scopeUri?: string;
+
+	/**
+	 * The configuration section asked for.
+	 */
+	section?: string;
+}
+```
+
+_Response_:
+* result: any[]
+* error: code and message set in case an exception happens during the 'workspace/configuration' request
+
+#### <a href="#workspace_didChangeWatchedFiles" name="workspace_didChangeWatchedFiles" class="anchor">DidChangeWatchedFiles Notification (:arrow_right:)</a>
+
+The watched files notification is sent from the client to the server when the client detects changes to files watched by the language client. It is recommended that servers register for these file events using the registration mechanism. In former implementations clients pushed file events without the server actively asking for it.
+
+Servers are allowed to run their own file watching mechanism and not rely on clients to provide file events. However this is not recommended due to the following reasons:
+
+- to our experience getting file watching on disk right is challenging, especially if it needs to be supported across multiple OSes.
+- file watching is not for free especially if the implementation uses some sort of polling and keeps a file tree in memory to compare time stamps (as for example some node modules do)
+- a client usually starts more than one server. If every server runs its own file watching it can become a CPU or memory problem.
+- in general there are more server than client implementations. So this problem is better solved on the client side.
+
+
+_Notification_:
+* method: 'workspace/didChangeWatchedFiles'
+* params: `DidChangeWatchedFilesParams` defined as follows:
+
+```typescript
+interface DidChangeWatchedFilesParams {
+	/**
+	 * The actual file events.
+	 */
+	changes: FileEvent[];
+}
+```
+
+Where FileEvents are described as follows:
+
+```typescript
+/**
+ * An event describing a file change.
+ */
+interface FileEvent {
+	/**
+	 * The file's URI.
+	 */
+	uri: DocumentUri;
+	/**
+	 * The change type.
+	 */
+	type: number;
+}
+
+/**
+ * The file event type.
+ */
+export namespace FileChangeType {
+	/**
+	 * The file got created.
+	 */
+	export const Created = 1;
+	/**
+	 * The file got changed.
+	 */
+	export const Changed = 2;
+	/**
+	 * The file got deleted.
+	 */
+	export const Deleted = 3;
+}
+```
+
+_Registration Options_: `DidChangeWatchedFilesRegistrationOptions` defined as follows
+
+```typescript
+/**
+ * Describe options to be used when registering for text document change events.
+ */
+export interface DidChangeWatchedFilesRegistrationOptions {
+	/**
+	 * The watchers to register.
+	 */
+	watchers: FileSystemWatcher[];
+}
+
+export interface FileSystemWatcher {
+	/**
+	 * The  glob pattern to watch.
+	 *
+	 * Glob patterns can have the following syntax:
+	 * - `*` to match one or more characters in a path segment
+	 * - `?` to match on one character in a path segment
+	 * - `**` to match any number of path segments, including none
+	 * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files)
+	 * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
+	 * - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
+	 */
+	globPattern: string;
+
+	/**
+	 * The kind of events of interest. If omitted it defaults
+	 * to WatchKind.Create | WatchKind.Change | WatchKind.Delete
+	 * which is 7.
+	 */
+	kind?: number;
+}
+
+export namespace WatchKind {
+	/**
+	 * Interested in create events.
+	 */
+	export const Create = 1;
+
+	/**
+	 * Interested in change events
+	 */
+	export const Change = 2;
+
+	/**
+	 * Interested in delete events
+	 */
+	export const Delete = 4;
+}
+```
+
+#### <a href="#workspace_symbol" name="workspace_symbol" class="anchor">Workspace Symbols Request (:leftwards_arrow_with_hook:)</a>
+
+The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string.
+
+_Request_:
+* method: 'workspace/symbol'
+* params: `WorkspaceSymbolParams` defined as follows:
+
+```typescript
+/**
+ * The parameters of a Workspace Symbol Request.
+ */
+interface WorkspaceSymbolParams {
+	/**
+	 * A non-empty query string
+	 */
+	query: string;
+}
+```
+
+_Response_:
+* result: `SymbolInformation[]` \| `null` as defined above.
+* error: code and message set in case an exception happens during the workspace symbol request.
+
+_Registration Options_: void
+
+
+#### <a href="#workspace_executeCommand" name="workspace_executeCommand" class="anchor">Execute a command (:leftwards_arrow_with_hook:)</a>
+
+The `workspace/executeCommand` request is sent from the client to the server to trigger command execution on the server. In most cases
+the server creates a `WorkspaceEdit` structure and applies the changes to the workspace using the request `workspace/applyEdit` which is
+sent from the server to the client.
+
+_Request:_
+* method: 'workspace/executeCommand'
+* params: `ExecuteCommandParams` defined as follows:
+
+```typescript
+export interface ExecuteCommandParams {
+
+	/**
+	 * The identifier of the actual command handler.
+	 */
+	command: string;
+	/**
+	 * Arguments that the command should be invoked with.
+	 */
+	arguments?: any[];
+}
+```
+
+The arguments are typically specified when a command is returned from the server to the client. Example requests that return a command are `textDocument/codeAction` or `textDocument/codeLens`.
+
+_Response_:
+* result: `any` \| `null`
+* error: code and message set in case an exception happens during the request.
+
+_Registration Options_: `ExecuteCommandRegistrationOptions` defined as follows:
+
+```typescript
+/**
+ * Execute command registration options.
+ */
+export interface ExecuteCommandRegistrationOptions {
+	/**
+	 * The commands to be executed on the server
+	 */
+	commands: string[]
+}
+```
+
+
+#### <a href="#workspace_applyEdit" name="workspace_applyEdit" class="anchor">Applies a WorkspaceEdit (:arrow_right_hook:)</a>
+
+The `workspace/applyEdit` request is sent from the server to the client to modify resource on the client side.
+
+_Request_:
+* method: 'workspace/applyEdit'
+* params: `ApplyWorkspaceEditParams` defined as follows:
+
+```typescript
+export interface ApplyWorkspaceEditParams {
+	/**
+	 * An optional label of the workspace edit. This label is
+	 * presented in the user interface for example on an undo
+	 * stack to undo the workspace edit.
+	 */
+	label?: string;
+
+	/**
+	 * The edits to apply.
+	 */
+	edit: WorkspaceEdit;
+}
+```
+
+_Response_:
+* result: `ApplyWorkspaceEditResponse` defined as follows:
+
+```typescript
+export interface ApplyWorkspaceEditResponse {
+	/**
+	 * Indicates whether the edit was applied or not.
+	 */
+	applied: boolean;
+}
+```
+* error: code and message set in case an exception happens during the request.
+
+
+#### <a href="#textDocument_didOpen" name="textDocument_didOpen" class="anchor">DidOpenTextDocument Notification (:arrow_right:)</a>
+
+The document open notification is sent from the client to the server to signal newly opened text documents. The document's truth is now managed by the client and the server must not try to read the document's truth using the document's Uri. Open in this sense means it is managed by the client. It doesn't necessarily mean that its content is presented in an editor. An open notification must not be sent more than once without a corresponding close notification send before. This means open and close notification must be balanced and the max open count for a particular textDocument is one. Note that a server's ability to fulfill requests is independent of whether a text document is open or closed.
+
+The `DidOpenTextDocumentParams` contain the language id the document is associated with. If the language Id of a document changes, the client needs to send a `textDocument/didClose` to the server followed by a `textDocument/didOpen` with the new language id if the server handles the new language id as well.
+
+_Notification_:
+* method: 'textDocument/didOpen'
+* params: `DidOpenTextDocumentParams` defined as follows:
+
+```typescript
+interface DidOpenTextDocumentParams {
+	/**
+	 * The document that was opened.
+	 */
+	textDocument: TextDocumentItem;
+}
+```
+
+_Registration Options_: `TextDocumentRegistrationOptions`
+
+
+#### <a href="#textDocument_didChange" name="textDocument_didChange" class="anchor">DidChangeTextDocument Notification (:arrow_right:)</a>
+
+The document change notification is sent from the client to the server to signal changes to a text document. In 2.0 the shape of the params has changed to include proper version numbers and language ids.
+
+_Notification_:
+* method: 'textDocument/didChange'
+* params: `DidChangeTextDocumentParams` defined as follows:
+
+```typescript
+interface DidChangeTextDocumentParams {
+	/**
+	 * The document that did change. The version number points
+	 * to the version after all provided content changes have
+	 * been applied.
+	 */
+	textDocument: VersionedTextDocumentIdentifier;
+
+	/**
+	 * The actual content changes. The content changes describe single state changes
+	 * to the document. So if there are two content changes c1 and c2 for a document
+	 * in state S then c1 move the document to S' and c2 to S''.
+	 */
+	contentChanges: TextDocumentContentChangeEvent[];
+}
+
+/**
+ * An event describing a change to a text document. If range and rangeLength are omitted
+ * the new text is considered to be the full content of the document.
+ */
+interface TextDocumentContentChangeEvent {
+	/**
+	 * The range of the document that changed.
+	 */
+	range?: Range;
+
+	/**
+	 * The length of the range that got replaced.
+	 */
+	rangeLength?: number;
+
+	/**
+	 * The new text of the range/document.
+	 */
+	text: string;
+}
+```
+
+_Registration Options_: `TextDocumentChangeRegistrationOptions` defined as follows:
+
+```typescript
+/**
+ * Describe options to be used when registering for text document change events.
+ */
+export interface TextDocumentChangeRegistrationOptions extends TextDocumentRegistrationOptions {
+	/**
+	 * How documents are synced to the server. See TextDocumentSyncKind.Full
+	 * and TextDocumentSyncKind.Incremental.
+	 */
+	syncKind: number;
+}
+```
+
+
+#### <a href="#textDocument_willSave" name="textDocument_willSave" class="anchor">WillSaveTextDocument Notification (:arrow_right:)</a>
+
+The document will save notification is sent from the client to the server before the document is actually saved.
+
+_Notification_:
+* method: 'textDocument/willSave'
+* params: `WillSaveTextDocumentParams` defined as follows:
+
+```typescript
+/**
+ * The parameters send in a will save text document notification.
+ */
+export interface WillSaveTextDocumentParams {
+	/**
+	 * The document that will be saved.
+	 */
+	textDocument: TextDocumentIdentifier;
+
+	/**
+	 * The 'TextDocumentSaveReason'.
+	 */
+	reason: number;
+}
+
+/**
+ * Represents reasons why a text document is saved.
+ */
+export namespace TextDocumentSaveReason {
+
+	/**
+	 * Manually triggered, e.g. by the user pressing save, by starting debugging,
+	 * or by an API call.
+	 */
+	export const Manual = 1;
+
+	/**
+	 * Automatic after a delay.
+	 */
+	export const AfterDelay = 2;
+
+	/**
+	 * When the editor lost focus.
+	 */
+	export const FocusOut = 3;
+}
+```
+
+_Registration Options_: `TextDocumentRegistrationOptions`
+
+
+#### <a href="#textDocument_willSaveWaitUntil" name="textDocument_willSaveWaitUntil" class="anchor">WillSaveWaitUntilTextDocument Request (:leftwards_arrow_with_hook:)</a>
+
+The document will save request is sent from the client to the server before the document is actually saved. The request can return an array of TextEdits which will be applied to the text document before it is saved. Please note that clients might drop results if computing the text edits took too long or if a server constantly fails on this request. This is done to keep the save fast and reliable.
+
+_Request_:
+* method: 'textDocument/willSaveWaitUntil'
+* params: `WillSaveTextDocumentParams`
+
+_Response_:
+* result:`TextEdit[]` \| `null`
+* error: code and message set in case an exception happens during the `willSaveWaitUntil` request.
+
+_Registration Options_: `TextDocumentRegistrationOptions`
+
+#### <a href="#textDocument_didSave" name="textDocument_didSave" class="anchor">DidSaveTextDocument Notification (:arrow_right:)</a>
+
+The document save notification is sent from the client to the server when the document was saved in the client.
+
+* method: 'textDocument/didSave'
+* params: `DidSaveTextDocumentParams` defined as follows:
+
+```typescript
+interface DidSaveTextDocumentParams {
+	/**
+	 * The document that was saved.
+	 */
+	textDocument: TextDocumentIdentifier;
+
+	/**
+	 * Optional the content when saved. Depends on the includeText value
+	 * when the save notification was requested.
+	 */
+	text?: string;
+}
+```
+
+_Registration Options_: `TextDocumentSaveRegistrationOptions` defined as follows:
+
+```typescript
+export interface TextDocumentSaveRegistrationOptions extends TextDocumentRegistrationOptions {
+	/**
+	 * The client is supposed to include the content on save.
+	 */
+	includeText?: boolean;
+}
+```
+
+#### <a href="#textDocument_didClose" name="textDocument_didClose" class="anchor">DidCloseTextDocument Notification (:arrow_right:)</a>
+
+The document close notification is sent from the client to the server when the document got closed in the client. The document's truth now exists where the document's Uri points to (e.g. if the document's Uri is a file Uri the truth now exists on disk). As with the open notification the close notification is about managing the document's content. Receiving a close notification doesn't mean that the document was open in an editor before. A close notification requires a previous open notification to be sent. Note that a server's ability to fulfill requests is independent of whether a text document is open or closed.
+
+_Notification_:
+* method: 'textDocument/didClose'
+* params: `DidCloseTextDocumentParams` defined as follows:
+
+```typescript
+interface DidCloseTextDocumentParams {
+	/**
+	 * The document that was closed.
+	 */
+	textDocument: TextDocumentIdentifier;
+}
+```
+
+_Registration Options_: `TextDocumentRegistrationOptions`
+
+
+#### <a href="#textDocument_publishDiagnostics" name="textDocument_publishDiagnostics" class="anchor">PublishDiagnostics Notification (:arrow_left:)</a>
+
+Diagnostics notification are sent from the server to the client to signal results of validation runs.
+
+Diagnostics are "owned" by the server so it is the server's responsibility to clear them if necessary. The following rule is used for VS Code servers that generate diagnostics:
+
+* if a language is single file only (for example HTML) then diagnostics are cleared by the server when the file is closed.
+* if a language has a project system (for example C#) diagnostics are not cleared when a file closes. When a project is opened all diagnostics for all files are recomputed (or read from a cache).
+
+When a file changes it is the server's responsibility to re-compute diagnostics and push them to the client. If the computed set is empty it has to push the empty array to clear former diagnostics. Newly pushed diagnostics always replace previously pushed diagnostics. There is no merging that happens on the client side.
+
+_Notification_:
+* method: 'textDocument/publishDiagnostics'
+* params: `PublishDiagnosticsParams` defined as follows:
+
+```typescript
+interface PublishDiagnosticsParams {
+	/**
+	 * The URI for which diagnostic information is reported.
+	 */
+	uri: DocumentUri;
+
+	/**
+	 * An array of diagnostic information items.
+	 */
+	diagnostics: Diagnostic[];
+}
+```
+
+#### <a href="#textDocument_completion" name="textDocument_completion" class="anchor">Completion Request (:leftwards_arrow_with_hook:)</a>
+
+The Completion request is sent from the client to the server to compute completion items at a given cursor position. Completion items are presented in the [IntelliSense](https://code.visualstudio.com/docs/editor/editingevolved#_intellisense) user interface. If computing full completion items is expensive, servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve'). This request is sent when a completion item is selected in the user interface. A typical use case is for example: the 'textDocument/completion' request doesn't fill in the `documentation` property for returned completion items since it is expensive to compute. When the item is selected in the user interface then a 'completionItem/resolve' request is sent with the selected completion item as a parameter. The returned completion item should have the documentation property filled in. The request can delay the computation of the `detail` and `documentation` properties. However, properties that are needed for the initial sorting and filtering, like `sortText`, `filterText`, `insertText`, and `textEdit` must be provided in the `textDocument/completion` response and must not be changed during resolve.
+
+_Request_:
+* method: 'textDocument/completion'
+* params: `CompletionParams` defined as follows:
+
+```typescript
+export interface CompletionParams extends TextDocumentPositionParams {
+
+	/**
+	 * The completion context. This is only available if the client specifies
+	 * to send this using `ClientCapabilities.textDocument.completion.contextSupport === true`
+	 */
+	context?: CompletionContext;
+}
+
+/**
+ * How a completion was triggered
+ */
+export namespace CompletionTriggerKind {
+	/**
+	 * Completion was triggered by typing an identifier (24x7 code
+	 * complete), manual invocation (e.g Ctrl+Space) or via API.
+	 */
+	export const Invoked: 1 = 1;
+
+	/**
+	 * Completion was triggered by a trigger character specified by
+	 * the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
+	 */
+	export const TriggerCharacter: 2 = 2;
+
+	/**
+	 * Completion was re-triggered as the current completion list is incomplete.
+	 */
+	export const TriggerForIncompleteCompletions: 3 = 3;
+}
+export type CompletionTriggerKind = 1 | 2 | 3;
+
+
+/**
+ * Contains additional information about the context in which a completion request is triggered.
+ */
+export interface CompletionContext {
+	/**
+	 * How the completion was triggered.
+	 */
+	triggerKind: CompletionTriggerKind;
+
+	/**
+	 * The trigger character (a single character) that has trigger code complete.
+	 * Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
+	 */
+	triggerCharacter?: string;
+}
+```
+
+_Response_:
+* result: `CompletionItem[]` \| `CompletionList` \| `null`. If a `CompletionItem[]` is provided it is interpreted to be complete. So it is the same as `{ isIncomplete: false, items }`
+
+```typescript
+/**
+ * Represents a collection of [completion items](#CompletionItem) to be presented
+ * in the editor.
+ */
+interface CompletionList {
+	/**
+	 * This list it not complete. Further typing should result in recomputing
+	 * this list.
+	 */
+	isIncomplete: boolean;
+
+	/**
+	 * The completion items.
+	 */
+	items: CompletionItem[];
+}
+
+/**
+ * Defines whether the insert text in a completion item should be interpreted as
+ * plain text or a snippet.
+ */
+namespace InsertTextFormat {
+	/**
+	 * The primary text to be inserted is treated as a plain string.
+	 */
+	export const PlainText = 1;
+
+	/**
+	 * The primary text to be inserted is treated as a snippet.
+	 *
+	 * A snippet can define tab stops and placeholders with `$1`, `$2`
+	 * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+	 * the end of the snippet. Placeholders with equal identifiers are linked,
+	 * that is typing in one will update others too.
+	 */
+	export const Snippet = 2;
+}
+
+type InsertTextFormat = 1 | 2;
+
+interface CompletionItem {
+	/**
+	 * The label of this completion item. By default
+	 * also the text that is inserted when selecting
+	 * this completion.
+	 */
+	label: string;
+
+	/**
+	 * The kind of this completion item. Based of the kind
+	 * an icon is chosen by the editor.
+	 */
+	kind?: number;
+
+	/**
+	 * A human-readable string with additional information
+	 * about this item, like type or symbol information.
+	 */
+	detail?: string;
+
+	/**
+	 * A human-readable string that represents a doc-comment.
+	 */
+	documentation?: string | MarkupContent;
+
+	/**
+	 * Indicates if this item is deprecated.
+	 */
+	deprecated?: boolean;
+
+	/**
+	 * Select this item when showing.
+	 *
+	 * *Note* that only one completion item can be selected and that the
+	 * tool / client decides which item that is. The rule is that the *first*
+	 * item of those that match best is selected.
+	 */
+	preselect?: boolean;
+
+	/**
+	 * A string that should be used when comparing this item
+	 * with other items. When `falsy` the label is used.
+	 */
+	sortText?: string;
+
+	/**
+	 * A string that should be used when filtering a set of
+	 * completion items. When `falsy` the label is used.
+	 */
+	filterText?: string;
+
+	/**
+	 * A string that should be inserted into a document when selecting
+	 * this completion. When `falsy` the label is used.
+	 *
+	 * The `insertText` is subject to interpretation by the client side.
+	 * Some tools might not take the string literally. For example
+	 * VS Code when code complete is requested in this example `con<cursor position>`
+	 * and a completion item with an `insertText` of `console` is provided it
+	 * will only insert `sole`. Therefore it is recommended to use `textEdit` instead
+	 * since it avoids additional client side interpretation.
+	 *
+	 * @deprecated Use textEdit instead.
+	 */
+	insertText?: string;
+
+	/**
+	 * The format of the insert text. The format applies to both the `insertText` property
+	 * and the `newText` property of a provided `textEdit`.
+	 */
+	insertTextFormat?: InsertTextFormat;
+
+	/**
+	 * An edit which is applied to a document when selecting this completion. When an edit is provided the value of
+	 * `insertText` is ignored.
+	 *
+	 * *Note:* The range of the edit must be a single line range and it must contain the position at which completion
+	 * has been requested.
+	 */
+	textEdit?: TextEdit;
+
+	/**
+	 * An optional array of additional text edits that are applied when
+	 * selecting this completion. Edits must not overlap (including the same insert position)
+	 * with the main edit nor with themselves.
+	 *
+	 * Additional text edits should be used to change text unrelated to the current cursor position
+	 * (for example adding an import statement at the top of the file if the completion item will
+	 * insert an unqualified type).
+	 */
+	additionalTextEdits?: TextEdit[];
+
+	/**
+	 * An optional set of characters that when pressed while this completion is active will accept it first and
+	 * then type that character. *Note* that all commit characters should have `length=1` and that superfluous
+	 * characters will be ignored.
+	 */
+	commitCharacters?: string[];
+
+	/**
+	 * An optional command that is executed *after* inserting this completion. *Note* that
+	 * additional modifications to the current document should be described with the
+	 * additionalTextEdits-property.
+	 */
+	command?: Command;
+
+	/**
+	 * An data entry field that is preserved on a completion item between
+	 * a completion and a completion resolve request.
+	 */
+	data?: any
+}
+
+/**
+ * The kind of a completion entry.
+ */
+namespace CompletionItemKind {
+	export const Text = 1;
+	export const Method = 2;
+	export const Function = 3;
+	export const Constructor = 4;
+	export const Field = 5;
+	export const Variable = 6;
+	export const Class = 7;
+	export const Interface = 8;
+	export const Module = 9;
+	export const Property = 10;
+	export const Unit = 11;
+	export const Value = 12;
+	export const Enum = 13;
+	export const Keyword = 14;
+	export const Snippet = 15;
+	export const Color = 16;
+	export const File = 17;
+	export const Reference = 18;
+	export const Folder = 19;
+	export const EnumMember = 20;
+	export const Constant = 21;
+	export const Struct = 22;
+	export const Event = 23;
+	export const Operator = 24;
+	export const TypeParameter = 25;
+}
+```
+* error: code and message set in case an exception happens during the completion request.
+
+_Registration Options_: `CompletionRegistrationOptions` options defined as follows:
+
+```typescript
+export interface CompletionRegistrationOptions extends TextDocumentRegistrationOptions {
+	/**
+	 * Most tools trigger completion request automatically without explicitly requesting
+	 * it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user
+	 * starts to type an identifier. For example if the user types `c` in a JavaScript file
+	 * code complete will automatically pop up present `console` besides others as a
+	 * completion item. Characters that make up identifiers don't need to be listed here.
+	 *
+	 * If code complete should automatically be trigger on characters not being valid inside
+	 * an identifier (for example `.` in JavaScript) list them in `triggerCharacters`.
+	 */
+	triggerCharacters?: string[];
+
+	/**
+	 * The server provides support to resolve additional
+	 * information for a completion item.
+	 */
+	resolveProvider?: boolean;
+}
+```
+
+Completion items support snippets (see `InsertTextFormat.Snippet`). The snippet format is as follows:
+
+##### Snippet Syntax
+
+The `body` of a snippet can use special constructs to control cursors and the text being inserted. The following are supported features and their syntaxes:
+
+##### Tab stops
+
+With tab stops, you can make the editor cursor move inside a snippet. Use `$1`, `$2` to specify cursor locations. The number is the order in whic