Initial documentation for a small sample of diagnostics and a script to generate a markdown file containing that documentation

Change-Id: I06602a29c95829b42add1d655ad8d7190ae7100a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105141
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 76e63a9..651d581 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -57,11 +57,30 @@
           "removing the unreachable catch clause.");
 
   /**
-   * Deprecated members should not be invoked or used.
-   *
    * Parameters:
    * 0: the name of the member
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a deprecated library or class
+  // member is used in a different package.
+  //
+  // #### Example
+  //
+  // If the method `m` in the class `C` is annotated with `@deprecated`, then
+  // the following code produces this diagnostic:
+  //
+  // ```dart
+  // void f(C c) {
+  //   c.!m!();
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // The documentation for declarations that are annotated with `@deprecated`
+  // should have documentation to indicate what code to use in place of the
+  // deprecated code.
   static const HintCode DEPRECATED_MEMBER_USE = const HintCode(
       'DEPRECATED_MEMBER_USE', "'{0}' is deprecated and shouldn't be used.",
       correction:
@@ -244,12 +263,32 @@
       "Only classes can be annotated as being immutable.");
 
   /**
-   * This hint is generated anywhere a @literal annotation is associated with
-   * anything other than a const constructor.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The meaning of the `@literal` annotation is only defined when it's applied
+  // to a const constructor.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // !@literal!
+  // var x;
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Remove the annotation:
+  //
+  // ```dart
+  // var x;
+  // ```
   static const HintCode INVALID_LITERAL_ANNOTATION = const HintCode(
       'INVALID_LITERAL_ANNOTATION',
-      "Only const constructors can be annotated as being literal.");
+      "Only const constructors can have the `@literal` annotation.");
 
   /**
    * This hint is generated anywhere where `@required` annotates a non named
@@ -618,13 +657,51 @@
       correction: "Try updating the SDK constraints.");
 
   /**
-   * A set literal is being used in code that is expected to run on versions of
-   * the SDK that did not support them.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a set literal is found in code
+  // that has an SDK constraint whose lower bound is less than 2.2. Set literals
+  // were not supported in earlier versions, so this code won't be able to run
+  // against earlier versions of the SDK.
+  //
+  // #### Example
+  //
+  // In a package that defines SDK constraints in the `pubspec.yaml` file that
+  // have a lower bound that's less than 2.2:
+  //
+  // ```yaml
+  // environment:
+  //   sdk: '>=2.1.0 <2.4.0'
+  // ```
+  //
+  // The following code generates this diagnostic:
+  //
+  // ```dart
+  // var s = !<int>{}!;
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If you don't need to support older versions of the SDK, then you can
+  // increase the SDK constraint to allow the syntax to be used:
+  //
+  // ```yaml
+  // environment:
+  //   sdk: '>=2.2.0 <2.4.0'
+  // ```
+  //
+  // If you do need to support older versions of the SDK, then replace the set
+  // literal with code that creates the set without the use of a literal:
+  //
+  // ```dart
+  // var s = new Set<int>();
+  // ```
   static const HintCode SDK_VERSION_SET_LITERAL = const HintCode(
       'SDK_VERSION_SET_LITERAL',
-      "Set literals were not supported until version 2.2, "
-          "but this code is required to be able to run on earlier versions.",
+      "Set literals weren't supported until version 2.2, "
+          "but this code must be able to run on earlier versions.",
       correction: "Try updating the SDK constraints.");
 
   /**
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 9363922..1b304fd 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -142,22 +142,142 @@
           correction: "Try removing the export of one of the libraries, or "
               "explicitly hiding the name in one of the export directives.");
 
+  /**
+   * No parameters.
+   */
+  // #### Description
+  //
+  // Because map and set literals use the same delimiters (`{` and `}`), the
+  // analyzer looks at the type arguments and the elements to determine which
+  // kind of literal you meant. When there are no type arguments and all of the
+  // elements are spread elements (which are allowed in both kinds of literals),
+  // then the analyzer uses the types of the expressions that are being spread.
+  // If all of the expressions have the type `Iterable`, then it's a set
+  // literal; if they all have the type `Map`, then it's a map literal.
+  //
+  // The analyzer produces this diagnostic when some of the expressions being
+  // spread have the type `Iterable` and others have the type `Map`, making it
+  // impossible for the analyzer to determine whether you are writing a map
+  // literal or a set literal.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // union(Map<String, String> a, List<String> b, Map<String, String> c) =>
+  //     {...a, ...b, ...c};
+  // ```
+  //
+  // The list `b` can only be spread into a set, and the maps `a` and `c` can
+  // only be spread into a map, and the literal can't be both.
+  //
+  // #### Common fixes
+  //
+  // There are two common ways to fix this problem. The first is to remove all
+  // of the spread elements of one kind or the other, so that the elements are
+  // consistent. In this case, that likely means removing the list (and
+  // deciding what to do about the now unused parameter):
+  //
+  // ```dart
+  // union(Map<String, String> a, List<String> b, Map<String, String> c) =>
+  //     {...a, ...c};
+  // ```
+  //
+  // The second fix is to change the elements of one kind into elements that are
+  // consistent with the other elements. For example, you could add the elements
+  // of the list as keys that map to themselves:
+  //
+  // ```dart
+  // union(Map<String, String> a, List<String> b, Map<String, String> c) =>
+  //     {...a, for (String s in b) s: s, ...c};
+  // ```
   static const CompileTimeErrorCode AMBIGUOUS_SET_OR_MAP_LITERAL_BOTH =
       const CompileTimeErrorCode(
           'AMBIGUOUS_SET_OR_MAP_LITERAL_BOTH',
-          "This literal must be both a map and a set, because some elements "
-              "spread a 'Map' and others spread an 'Iterable', but that isn't "
-              "allowed.",
+          "This literal contains both 'Map' and 'Iterable' spreads, "
+              "which makes it impossible to determine whether the literal is "
+              "a map or a set.",
           correction:
               "Try removing or changing some of the elements so that all of "
               "the elements are consistent.");
 
+  /**
+   * No parameters.
+   */
+  // #### Description
+  //
+  // Because map and set literals use the same delimiters (`‘{` and `}`), the
+  // analyzer looks at the type arguments and the elements to determine which
+  // kind of literal you meant. When there are no type arguments and all of the
+  // elements are spread elements (which are allowed in both kinds of literals)
+  // then the analyzer uses the types of the expressions that are being spread
+  // to decide. If all of the expressions have the type `Iterable`, then it's a
+  // set literal, if they all have the type `Map`, then it's a map literal.
+  //
+  // This diagnostic is produced when none of the expressions being spread has a
+  // type that allows the analyzer to decide whether you were writing a map
+  // literal or a set literal.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // union(a, b) => !{...a, ...b}!;
+  // ```
+  //
+  // The problem occurs because there are no type arguments, and there is no
+  // information about the type of either `a` or `b`.
+  //
+  // #### Common fixes
+  //
+  // There are three common ways to fix this problem. The first is to add type
+  // arguments to the literal. For example, if the literal is intended to be a
+  // map literal, you might write something like this:
+  //
+  // ```dart
+  // union(a, b) => <String, String>{...a, ...b};
+  // ```
+  //
+  // The second fix is to add type information so that the expressions have
+  // either the type `Iterable` or the type `Map`. You could add an explicit
+  // cast or, in this case, add types to the declarations of the two parameters:
+  //
+  // ```dart
+  // union(List<int> a, List<int> b) => {...a, ...b};
+  // ```
+  //
+  // The third fix is to add context information. In this case, that means
+  // adding a return type to the function:
+  //
+  // ```dart
+  // Set<String> union(a, b) => {...a, ...b};
+  // ```
+  //
+  // In other cases, you might add a type somewhere else. For example, say the
+  // original code looks like this:
+  //
+  // ```dart
+  // union(a, b) {
+  //   var x = {...a, ...b};
+  //   return x;
+  // }
+  // ```
+  //
+  // You might add a type annotation on `x`, like this:
+  //
+  // ```dart
+  // union(a, b) {
+  //   Map<String, String> x = {...a, ...b};
+  //   return x;
+  // }
+  // ```
   static const CompileTimeErrorCode AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER =
       const CompileTimeErrorCode(
           'AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER',
-          "This literal must be either a map or a set, but none of the "
-              "elements have enough type information to know which, and that isn't "
-              "allowed.",
+          "This literal must be either a map or a set, but the elements don't "
+              "have enough type information for type inference to work.",
           correction:
               "Try adding type arguments to the literal (one for sets, two "
               "for maps).");
@@ -820,11 +940,40 @@
           correction: "Try removing the default value.");
 
   /**
-   * It is an error if a required named parameter has a default value.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a named parameter has both the
+  // `required` modifier and a default value. If the parameter is required, then
+  // a value for the parameter is always provided at the call sites, so the
+  // default value can never be used.
+  //
+  // #### Example
+  //
+  // The following code generates this diagnostic:
+  //
+  // ```dart
+  // void log({required String !message! = 'no message'}) {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the parameter is really required, then remove the default value:
+  //
+  // ```dart
+  // void log({required String message}) {}
+  // ```
+  //
+  // If the parameter isn't always required, then remove the `required`
+  // modifier:
+  //
+  // ```dart
+  // void log({String message = 'no message'}) {}
+  // ```
   static const CompileTimeErrorCode DEFAULT_VALUE_ON_REQUIRED_PARAMETER =
       const CompileTimeErrorCode('DEFAULT_VALUE_ON_REQUIRED_PARAMETER',
-          "Required named parameters cannot have a default value.",
+          "Required named parameters can't have a default value.",
           correction: "Try removing either the default value or the 'required' "
               "modifier.");
 
@@ -932,9 +1081,33 @@
           "The exported library '{0}' can't have a part-of directive.",
           correction: "Try exporting the library that the part is a part of.");
 
+  /**
+   * No parameters.
+   */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when the analyzer finds an
+  // expression, rather than a map entry, in what appears to be a map literal.
+  //
+  // #### Example
+  //
+  // The following code generates this diagnostic:
+  //
+  // ```dart
+  // var map = <String, int>{'a': 0, 'b': 1, !'c'!};
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the expression is intended to compute either a key or a value in an
+  // entry, fix the issue by completing the code:
+  //
+  // ```dart
+  // var map = <String, int>{'a': 0, 'b': 1, 'c': 2};
+  // ```
   static const CompileTimeErrorCode EXPRESSION_IN_MAP =
       const CompileTimeErrorCode(
-          'EXPRESSION_IN_MAP', "Expressions cannot be used in a map literal.",
+          'EXPRESSION_IN_MAP', "Expressions can't be used in a map literal.",
           correction:
               "Try removing the expression or converting it to be a map entry.");
 
@@ -1707,13 +1880,50 @@
           correction: "Check your Dart SDK installation for completeness.");
 
   /**
-   * It is an error if an optional parameter (named or otherwise) with no
-   * default value has a potentially non-nullable type.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when an optional parameter doesn't
+  // have a default value, but has a
+  // <a href=”#potentially-non-nullable”>potentially non-nullable</a> type.
+  // Optional parameters that have no explicit default value have an implicit
+  // default value of `null`. If the type of the parameter doesn't allow the
+  // parameter to have a value of null, then the implicit default value is not
+  // valid.
+  //
+  // #### Example
+  //
+  // The following code generates this diagnostic:
+  //
+  // ```dart
+  // void log({String !message!}) {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the parameter can have the value `null`, then add a question mark after
+  // the type annotation:
+  //
+  // ```dart
+  // void log({String? message}) {}
+  // ```
+  //
+  // If the parameter can't be null, then either provide a default value:
+  //
+  // ```dart
+  // void log({String message = ''}) {}
+  // ```
+  //
+  // or add the `required` modifier to the parameter:
+  //
+  // ```dart
+  // void log({required String message}) {}
+  // ```
   static const CompileTimeErrorCode MISSING_DEFAULT_VALUE_FOR_PARAMETER =
       const CompileTimeErrorCode(
           'MISSING_DEFAULT_VALUE_FOR_PARAMETER',
-          "The parameter '{0}' cannot have a value of 'null' because of its "
+          "The parameter '{0}' can't have a value of 'null' because of its "
               "type, so it must either be a required parameter or have a "
               "default value.",
           correction:
@@ -2241,6 +2451,33 @@
           "{0} required argument(s) expected, but {1} found.",
           correction: "Try adding the missing arguments.");
 
+  /**
+   * No parameters.
+   */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when the static type of the
+  // expression of a spread element that appears in either a list literal or a
+  // set literal doesn't implement the type `Iterable`.
+  //
+  // #### Example
+  //
+  // The following code generates this diagnostic:
+  //
+  // ```dart
+  // var m = <String, int>{'a': 0, 'b': 1};
+  // var s = <String>{...m};
+  // ```
+  //
+  // #### Common fixes
+  //
+  // The most common fix is to replace the expression with one that produces an
+  // iterable object:
+  //
+  // ```dart
+  // var m = <String, int>{'a': 0, 'b': 1};
+  // var s = <String>{...m.keys};
+  // ```
   static const CompileTimeErrorCode NOT_ITERABLE_SPREAD =
       const CompileTimeErrorCode('NOT_ITERABLE_SPREAD',
           "Spread elements in list or set literals must implement 'Iterable'.");
@@ -2279,12 +2516,39 @@
           correction: "Try removing the question mark.");
 
   /**
-   * It is a compile-time error for a class to extend, implement, or mixin a
-   * type of the form T? for any T.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a class declaration uses an
+  // extends clause to specify a superclass, and the type that's specified is a
+  // nullable type.
+  //
+  // The reason the supertype is a _type_ rather than a class name is to allow
+  // you to control the signatures of the members to be inherited from the
+  // supertype, such as by specifying type arguments. However, the nullability
+  // of a type doesn't change the signatures of any members, so there isn't any
+  // reason to allow the nullability to be specified when used in the extends
+  // clause.
+  //
+  // #### Example
+  //
+  // The following code generates this diagnostic:
+  //
+  // ```dart
+  // class Invalid extends !Duration?! {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // The most common fix is to remove the question mark:
+  //
+  // ```dart
+  // class Invalid extends Duration {}
+  // ```
   static const CompileTimeErrorCode NULLABLE_TYPE_IN_EXTENDS_CLAUSE =
       const CompileTimeErrorCode('NULLABLE_TYPE_IN_EXTENDS_CLAUSE',
-          "A class cannot extend a nullable type.",
+          "A class can't extend a nullable type.",
           correction: "Try removing the question mark.");
 
   /**
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
new file mode 100644
index 0000000..b3fc35b
--- /dev/null
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -0,0 +1,415 @@
+---
+title: Diagnostics
+description: Details for diagnostics produced by the Dart analyzer.
+---
+
+This page lists diagnostic messages produced by the Dart analyzer,
+with details about what those messages mean and how you can fix your code.
+For more information about the analyzer, see
+[Customizing static analysis](/guides/language/analysis-options).
+
+## Glossary
+
+This page uses the following terms.
+
+### Potentially non-nullable
+
+A type is _potentially non-nullable_ if it's either explicitly non-nullable or
+if it's a type parameter. The latter case is included because the actual runtime
+type might be non-nullable.
+
+## Diagnostics
+
+The analyzer produces the following diagnostics for code that
+doesn't conform to the language specification or
+that might work in unexpected ways.
+
+### ambiguous\_set\_or\_map\_literal\_both
+
+_This literal contains both 'Map' and 'Iterable' spreads, which makes it
+impossible to determine whether the literal is a map or a set._
+
+#### Description
+
+Because map and set literals use the same delimiters (`{` and `}`), the
+analyzer looks at the type arguments and the elements to determine which
+kind of literal you meant. When there are no type arguments and all of the
+elements are spread elements (which are allowed in both kinds of literals),
+then the analyzer uses the types of the expressions that are being spread.
+If all of the expressions have the type `Iterable`, then it's a set
+literal; if they all have the type `Map`, then it's a map literal.
+
+The analyzer produces this diagnostic when some of the expressions being
+spread have the type `Iterable` and others have the type `Map`, making it
+impossible for the analyzer to determine whether you are writing a map
+literal or a set literal.
+
+#### Example
+
+The following code produces this diagnostic:
+
+```dart
+union(Map<String, String> a, List<String> b, Map<String, String> c) =>
+    {...a, ...b, ...c};
+```
+
+The list `b` can only be spread into a set, and the maps `a` and `c` can
+only be spread into a map, and the literal can't be both.
+
+#### Common fixes
+
+There are two common ways to fix this problem. The first is to remove all
+of the spread elements of one kind or the other, so that the elements are
+consistent. In this case, that likely means removing the list (and
+deciding what to do about the now unused parameter):
+
+```dart
+union(Map<String, String> a, List<String> b, Map<String, String> c) =>
+    {...a, ...c};
+```
+
+The second fix is to change the elements of one kind into elements that are
+consistent with the other elements. For example, you could add the elements
+of the list as keys that map to themselves:
+
+```dart
+union(Map<String, String> a, List<String> b, Map<String, String> c) =>
+    {...a, for (String s in b) s: s, ...c};
+```
+
+### ambiguous\_set\_or\_map\_literal\_either
+
+_This literal must be either a map or a set, but the elements don't have enough
+type information for type inference to work._
+
+#### Description
+
+Because map and set literals use the same delimiters (`‘{` and `}`), the
+analyzer looks at the type arguments and the elements to determine which
+kind of literal you meant. When there are no type arguments and all of the
+elements are spread elements (which are allowed in both kinds of literals)
+then the analyzer uses the types of the expressions that are being spread
+to decide. If all of the expressions have the type `Iterable`, then it's a
+set literal, if they all have the type `Map`, then it's a map literal.
+
+This diagnostic is produced when none of the expressions being spread has a
+type that allows the analyzer to decide whether you were writing a map
+literal or a set literal.
+
+#### Example
+
+The following code produces this diagnostic:
+
+```dart
+union(a, b) => !{...a, ...b}!;
+```
+
+The problem occurs because there are no type arguments, and there is no
+information about the type of either `a` or `b`.
+
+#### Common fixes
+
+There are three common ways to fix this problem. The first is to add type
+arguments to the literal. For example, if the literal is intended to be a
+map literal, you might write something like this:
+
+```dart
+union(a, b) => <String, String>{...a, ...b};
+```
+
+The second fix is to add type information so that the expressions have
+either the type `Iterable` or the type `Map`. You could add an explicit
+cast or, in this case, add types to the declarations of the two parameters:
+
+```dart
+union(List<int> a, List<int> b) => {...a, ...b};
+```
+
+The third fix is to add context information. In this case, that means
+adding a return type to the function:
+
+```dart
+Set<String> union(a, b) => {...a, ...b};
+```
+
+In other cases, you might add a type somewhere else. For example, say the
+original code looks like this:
+
+```dart
+union(a, b) {
+  var x = {...a, ...b};
+  return x;
+}
+```
+
+You might add a type annotation on `x`, like this:
+
+```dart
+union(a, b) {
+  Map<String, String> x = {...a, ...b};
+  return x;
+}
+```
+
+### default\_value\_on\_required\_parameter
+
+_Required named parameters can't have a default value._
+
+#### Description
+
+The analyzer produces this diagnostic when a named parameter has both the
+`required` modifier and a default value. If the parameter is required, then
+a value for the parameter is always provided at the call sites, so the
+default value can never be used.
+
+#### Example
+
+The following code generates this diagnostic:
+
+```dart
+void log({required String !message! = 'no message'}) {}
+```
+
+#### Common fixes
+
+If the parameter is really required, then remove the default value:
+
+```dart
+void log({required String message}) {}
+```
+
+If the parameter isn't always required, then remove the `required`
+modifier:
+
+```dart
+void log({String message = 'no message'}) {}
+```
+
+### deprecated\_member\_use
+
+_'{0}' is deprecated and shouldn't be used._
+
+#### Description
+
+The analyzer produces this diagnostic when a deprecated library or class
+member is used in a different package.
+
+#### Example
+
+If the method `m` in the class `C` is annotated with `@deprecated`, then
+the following code produces this diagnostic:
+
+```dart
+void f(C c) {
+  c.!m!();
+}
+```
+
+#### Common fixes
+
+The documentation for declarations that are annotated with `@deprecated`
+should have documentation to indicate what code to use in place of the
+deprecated code.
+
+### expression\_in\_map
+
+_Expressions can't be used in a map literal._
+
+#### Description
+
+The analyzer produces this diagnostic when the analyzer finds an
+expression, rather than a map entry, in what appears to be a map literal.
+
+#### Example
+
+The following code generates this diagnostic:
+
+```dart
+var map = <String, int>{'a': 0, 'b': 1, !'c'!};
+```
+
+#### Common fixes
+
+If the expression is intended to compute either a key or a value in an
+entry, fix the issue by completing the code:
+
+```dart
+var map = <String, int>{'a': 0, 'b': 1, 'c': 2};
+```
+
+### invalid\_literal\_annotation
+
+_Only const constructors can have the `@literal` annotation._
+
+#### Description
+
+The meaning of the `@literal` annotation is only defined when it's applied
+to a const constructor.
+
+#### Example
+
+The following code produces this diagnostic:
+
+```dart
+!@literal!
+var x;
+```
+
+#### Common fixes
+
+Remove the annotation:
+
+```dart
+var x;
+```
+
+### missing\_default\_value\_for\_parameter
+
+_The parameter '{0}' can't have a value of 'null' because of its type, so it
+must either be a required parameter or have a default value._
+
+#### Description
+
+The analyzer produces this diagnostic when an optional parameter doesn't
+have a default value, but has a
+<a href=”#potentially-non-nullable”>potentially non-nullable</a> type.
+Optional parameters that have no explicit default value have an implicit
+default value of `null`. If the type of the parameter doesn't allow the
+parameter to have a value of null, then the implicit default value is not
+valid.
+
+#### Example
+
+The following code generates this diagnostic:
+
+```dart
+void log({String !message!}) {}
+```
+
+#### Common fixes
+
+If the parameter can have the value `null`, then add a question mark after
+the type annotation:
+
+```dart
+void log({String? message}) {}
+```
+
+If the parameter can't be null, then either provide a default value:
+
+```dart
+void log({String message = ''}) {}
+```
+
+or add the `required` modifier to the parameter:
+
+```dart
+void log({required String message}) {}
+```
+
+### not\_iterable\_spread
+
+_Spread elements in list or set literals must implement 'Iterable'._
+
+#### Description
+
+The analyzer produces this diagnostic when the static type of the
+expression of a spread element that appears in either a list literal or a
+set literal doesn't implement the type `Iterable`.
+
+#### Example
+
+The following code generates this diagnostic:
+
+```dart
+var m = <String, int>{'a': 0, 'b': 1};
+var s = <String>{...m};
+```
+
+#### Common fixes
+
+The most common fix is to replace the expression with one that produces an
+iterable object:
+
+```dart
+var m = <String, int>{'a': 0, 'b': 1};
+var s = <String>{...m.keys};
+```
+
+### nullable\_type\_in\_extends\_clause
+
+_A class can't extend a nullable type._
+
+#### Description
+
+The analyzer produces this diagnostic when a class declaration uses an
+extends clause to specify a superclass, and the type that's specified is a
+nullable type.
+
+The reason the supertype is a _type_ rather than a class name is to allow
+you to control the signatures of the members to be inherited from the
+supertype, such as by specifying type arguments. However, the nullability
+of a type doesn't change the signatures of any members, so there isn't any
+reason to allow the nullability to be specified when used in the extends
+clause.
+
+#### Example
+
+The following code generates this diagnostic:
+
+```dart
+class Invalid extends !Duration?! {}
+```
+
+#### Common fixes
+
+The most common fix is to remove the question mark:
+
+```dart
+class Invalid extends Duration {}
+```
+
+### sdk\_version\_set\_literal
+
+_Set literals weren't supported until version 2.2, but this code must be able to
+run on earlier versions._
+
+#### Description
+
+The analyzer produces this diagnostic when a set literal is found in code
+that has an SDK constraint whose lower bound is less than 2.2. Set literals
+were not supported in earlier versions, so this code won't be able to run
+against earlier versions of the SDK.
+
+#### Example
+
+In a package that defines SDK constraints in the `pubspec.yaml` file that
+have a lower bound that's less than 2.2:
+
+```yaml
+environment:
+  sdk: '>=2.1.0 <2.4.0'
+```
+
+The following code generates this diagnostic:
+
+```dart
+var s = !<int>{}!;
+```
+
+#### Common fixes
+
+If you don't need to support older versions of the SDK, then you can
+increase the SDK constraint to allow the syntax to be used:
+
+```yaml
+environment:
+  sdk: '>=2.2.0 <2.4.0'
+```
+
+If you do need to support older versions of the SDK, then replace the set
+literal with code that creates the set without the use of a literal:
+
+```dart
+var s = new Set<int>();
+```
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
new file mode 100644
index 0000000..17350b5
--- /dev/null
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -0,0 +1,216 @@
+// 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:io';
+
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:front_end/src/testing/package_root.dart' as package_root;
+import 'package:path/src/context.dart';
+
+/// Generate the file `diagnostics.md` based on the documentation associated
+/// with the declarations of the error codes.
+void main() async {
+  Context pathContext = PhysicalResourceProvider.INSTANCE.pathContext;
+  String packageRoot = pathContext.normalize(package_root.packageRoot);
+  String analyzerPath = pathContext.join(packageRoot, 'analyzer');
+  List<String> docPaths = [
+    pathContext.join(
+        analyzerPath, 'lib', 'src', 'dart', 'error', 'hint_codes.dart'),
+    pathContext.join(analyzerPath, 'lib', 'src', 'error', 'codes.dart'),
+  ];
+  String outputPath =
+      pathContext.join(analyzerPath, 'tool', 'diagnostics', 'diagnostics.md');
+
+  DocumentationGenerator generator = DocumentationGenerator(docPaths);
+  generator.writeDocumentation(outputPath);
+}
+
+/// A class used to generate diagnostic documentation.
+class DocumentationGenerator {
+  /// The absolute paths of the files containing the declarations of the error
+  /// codes.
+  final List<String> docPaths;
+
+  /// A map from the name of a diagnostic code to the lines of the documentation
+  /// for that code.
+  Map<String, List<String>> docsByCode = {};
+
+  /// Initialize a newly created documentation generator.
+  DocumentationGenerator(this.docPaths) {
+    _extractAllDocs();
+  }
+
+  /// Write the documentation to the file at the given [outputPath].
+  void writeDocumentation(String outputPath) async {
+    IOSink sink = File(outputPath).openWrite();
+    _writeHeader(sink);
+    _writeGlossary(sink);
+    _writeDiagnostics(sink);
+    await sink.flush();
+    await sink.close();
+  }
+
+  /// Return a version of the [text] in which characters that have special
+  /// meaning in markdown have been escaped.
+  String _escape(String text) {
+    return text.replaceAll('_', '\\_');
+  }
+
+  /// Extract documentation from all of the files containing the definitions of
+  /// diagnostics.
+  void _extractAllDocs() {
+    AnalysisContextCollection collection = new AnalysisContextCollection(
+        includedPaths: docPaths,
+        resourceProvider: PhysicalResourceProvider.INSTANCE);
+    for (String docPath in docPaths) {
+      _extractDocs(_parse(collection, docPath));
+    }
+  }
+
+  /// Extract documentation from the given [field] declaration.
+  List<String> _extractDoc(FieldDeclaration field) {
+    Token comments = field.firstTokenAfterCommentAndMetadata.precedingComments;
+    if (comments == null) {
+      return null;
+    }
+    List<String> docs = [];
+    while (comments != null) {
+      String lexeme = comments.lexeme;
+      if (lexeme.startsWith('// TODO')) {
+        break;
+      } else if (lexeme.startsWith('// ')) {
+        docs.add(lexeme.substring(3));
+      } else if (lexeme == '//') {
+        docs.add('');
+      }
+      comments = comments.next;
+    }
+    if (docs.isEmpty) {
+      return null;
+    }
+    return docs;
+  }
+
+  /// Extract documentation from the file that was parsed to produce the given
+  /// [result].
+  void _extractDocs(ParsedUnitResult result) {
+    CompilationUnit unit = result.unit;
+    for (CompilationUnitMember declaration in unit.declarations) {
+      if (declaration is ClassDeclaration) {
+        for (ClassMember member in declaration.members) {
+          if (member is FieldDeclaration) {
+            List<String> docs = _extractDoc(member);
+            if (docs != null) {
+              VariableDeclaration variable = member.fields.variables[0];
+              String variableName = variable.name.name;
+              if (docsByCode.containsKey(variableName)) {
+                throw StateError('Duplicate diagnostic code');
+              }
+              String message =
+                  ((variable.initializer as InstanceCreationExpression)
+                          .argumentList
+                          .arguments[1] as StringLiteral)
+                      .stringValue;
+              docs = [
+                '### ${_escape(variableName.toLowerCase())}',
+                '',
+                ..._split('_${_escape(message)}_'),
+                '',
+                ...docs,
+              ];
+              docsByCode[variableName] = docs;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /// Use the analysis context [collection] to parse the file at the given
+  /// [path] and return the result.
+  ParsedUnitResult _parse(AnalysisContextCollection collection, String path) {
+    AnalysisSession session = collection.contextFor(path).currentSession;
+    if (session == null) {
+      throw new StateError('No session for "$path"');
+    }
+    ParsedUnitResult result = session.getParsedUnit(path);
+    if (result.state != ResultState.VALID) {
+      throw new StateError('Unable to parse "$path"');
+    }
+    return result;
+  }
+
+  /// Split the [message] into multiple lines, each of which is less than 80
+  /// characters long.
+  List<String> _split(String message) {
+    // This uses a brute force approach because we don't expect to have messages
+    // that need to be split more than once.
+    int length = message.length;
+    if (length <= 80) {
+      return [message];
+    }
+    int endIndex = message.lastIndexOf(' ', 80);
+    if (endIndex < 0) {
+      return [message];
+    }
+    return [message.substring(0, endIndex), message.substring(endIndex + 1)];
+  }
+
+  /// Write the documentation for all of the diagnostics.
+  void _writeDiagnostics(IOSink sink) {
+    sink.write('''
+
+## Diagnostics
+
+The analyzer produces the following diagnostics for code that
+doesn't conform to the language specification or
+that might work in unexpected ways.
+''');
+    List<String> errorCodes = docsByCode.keys.toList();
+    errorCodes.sort();
+    for (String errorCode in errorCodes) {
+      List<String> docs = docsByCode[errorCode];
+      sink.writeln();
+      for (String line in docs) {
+        sink.writeln(line);
+      }
+    }
+  }
+
+  /// Write the glossary.
+  void _writeGlossary(IOSink sink) {
+    sink.write('''
+
+## Glossary
+
+This page uses the following terms.
+
+### Potentially non-nullable
+
+A type is _potentially non-nullable_ if it's either explicitly non-nullable or
+if it's a type parameter. The latter case is included because the actual runtime
+type might be non-nullable.
+''');
+  }
+
+  /// Write the header of the file.
+  void _writeHeader(IOSink sink) {
+    sink.write('''
+---
+title: Diagnostics
+description: Details for diagnostics produced by the Dart analyzer.
+---
+
+This page lists diagnostic messages produced by the Dart analyzer,
+with details about what those messages mean and how you can fix your code.
+For more information about the analyzer, see
+[Customizing static analysis](/guides/language/analysis-options).
+''');
+  }
+}