[linter] Update writing lints doc for current process

Contributes to https://github.com/dart-lang/sdk/issues/59696 by updating the writing lint docs for the current process.
I left updating the bootstrapping tool for a separate CL to keep this easier to review.

Based on what direction we go for the messages.yaml file, this doc will continue to change and hopefully get simpler.

Change-Id: I706e9438fbd6acdba41dd7198ad3b5afd5acbe4e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/400420
Commit-Queue: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/linter/doc/writing-lints.md b/pkg/linter/doc/writing-lints.md
index 2beaf3e..5bd241d 100644
--- a/pkg/linter/doc/writing-lints.md
+++ b/pkg/linter/doc/writing-lints.md
@@ -1,154 +1,432 @@
-# Writing Lints
+# Writing lints
 
-Preliminary notes on writing lints.
+Preliminary notes on writing lints for the
+Dart analysis server's built-in linter rules.
 
-## Lint Criteria
+> [!WARNING]
+> The process of writing and documenting lints is
+> currently being changed and streamlined.
+> Expect changes to this document and the process.
 
-Borrowing heavily from the criteria for [adding new checks to errorprone],
+## Lint criteria
+
+Borrowing heavily from the criteria for [adding new checks to errorprone][],
 lints should have the following properties.
 
 Dart lints:
 
-* should be easy to understand.  The problem should be obvious once the linter
-  points it out.
-* should have a correspondingly easy fix.  For example, "Remove this type
-  annotation", or "Delete these braces", not "Introduce a new subclass and
-  override methods A, B, and C."
+* should be easy to understand.
+  The problem should be obvious once the analyzer points it out.
+* should have a correspondingly easy fix.
+  For example, "Remove this type annotation", or "Delete these braces",
+  not "Introduce a new subclass and override methods A, B, and C."
 * should have *few* false positives.
 
-## Lint Properties
+[adding new checks to errorprone]: https://github.com/google/error-prone/wiki/Criteria-for-new-checks
 
-Every lint has a:
+## Lint properties
 
-**Name.** A short name using [Dart package naming conventions].  Naming is
-*hard* but strive to be concise and consistent.  Prefer to use the _problem_ as
-the name, as in the existing lints `control_flow_in_finally` and
-`empty_catches`.  Do not start a lint's name with "always", "avoid", or
-"prefer".  Where possible, use existing rules for inspiration and observe the
-rules of [parallel construction].
+Every lint has the following properties, some for implementation purposes,
+and others for generating documentation.
 
-**Description.** A short description of the lint, suitable for printing in
-console output.  For example:
+### Name
 
-```
-[lint] DO name types using UpperCamelCase.
+A short name using [Dart package naming conventions][].
+
+Naming is *hard* but strive to be concise and consistent.
+
+Prefer to use the _problem_ as the name to be consistent with other diagnotics,
+similar to the existing lints `control_flow_in_finally` and `empty_catches`.
+
+Don't start a lint's name with "always", "avoid", or "prefer".
+Where possible, use existing rules for inspiration and
+observe the rules of [parallel construction][].
+
+[Dart package naming conventions]: https://dart.dev/tools/pub/pubspec#name
+[parallel construction]: https://en.wikipedia.org/wiki/Parallelism_(grammar)
+
+### Lint codes
+
+Every lint has at least one lint code associated with it.
+A lint code defines the problem and correction messages that
+are shown to developers when reporting a lint.
+
+Lint codes are defined in the [`messages.yaml`][] file,
+with other lint details also added to the entry.
+
+```yaml
+control_flow_in_finally:
+  problemMessage: "Use of '{0}' in a 'finally' clause."
+  correctionMessage: "Try restructuring the code."
 ```
 
-**Kind.** The first word in the description should identify the *kind* of lint
-where kinds are derived from the [style guide]. In summary:
+If a lint covers situations that would benefit from
+different problem and/or correction messages,
+multiple codes can be added to the file.
+They should each have a unique name, sharing the name of the lint as a prefix,
+and specify the `sharedName` property as the lint name:
 
-* ***DO*** guidelines describe practices that should always be followed.  There
-will almost never be a valid reason to stray from them.
+```yaml
+unnecessary_final_with_type:
+  sharedName: unnecessary_final
+  problemMessage: "Local variables should not be marked as 'final'."
+  correctionMessage: "Remove the 'final'."
+  # ...
+unnecessary_final_without_type:
+  sharedName: unnecessary_final
+  problemMessage: "Local variables should not be marked as 'final'."
+  correctionMessage: "Replace 'final' with 'var'."
+```
 
-* ***DON'T*** guidelines are the converse: things that are almost never a good
-idea.  You'll note there are few of these here.  Guidelines like these in other
-languages help to avoid the pitfalls that appear over time.  Dart is new enough
-that we can just fix those pitfalls directly instead of putting up ropes around
-them.
+Only one of the entries needs to include the other details of the lint.
 
-* ***PREFER*** guidelines are practices that you should follow.  However, there
-may be circumstances where it makes sense to do otherwise.  Just make sure you
-understand the full implications of ignoring the guideline when you do.
+To access the lint codes for enumerating them or reporting them,
+generate them using `dart run pkg/linter/tool/generate_lints.dart`
+and access them through static getters on `LinterLintCode`:
 
-* ***AVOID*** guidelines are the dual to "prefer": stuff you shouldn't do but
-where there may be good reasons to on rare occasions.
+```dart
+@override
+List<LintCode> get lintCodes => [
+      LinterLintCode.unnecessary_final_with_type,
+      LinterLintCode.unnecessary_final_without_type
+    ];
+```
 
-* ***CONSIDER*** guidelines are practices that you might or might not want to
-follow, depending on circumstances, precedents, and your own preference.
+### Short description
 
-**Detailed Description.** In addition to the short description, a lint rule
-should have more detailed rationale with code examples, ideally *good* and
-*bad*.  The [style guide] is a great source for inspiration.  Many style
-recommendations have been directly translated to lints as enumerated
-[here][lints].
+A short, one to two sentence, summary of the lint that provides
+enough context for developers to roughly understand the situations
+a lint will trigger and perhaps how to resolve it.
 
-**Group.**  A grouping.  For example, *Style Guide* aggregates style guide
-derived lints.
+For example, `control_flow_in_finally` has a description of:
 
-**Maturity.** Rules can be further distinguished by maturity.  Unqualified rules
-are considered stable, while others may be marked *EXPERIMENTAL* or *PROPOSED*
-to indicate that they are under review.
+```
+Avoid control flow in `finally` blocks.
+```
+
+Each short description should begin with a guiding term that
+corresponds to [Effective Dart's guidelines][]:
+
+- `Do`
+- `Don't`
+- `Prefer`
+- `Avoid`
+- `Consider`
+
+[Effective Dart's guidelines]: https://dart.dev/effective-dart#how-to-read-the-guides
+
+Currently, short descriptions are specified in the
+super constructor call of the lint implementation:
+
+```dart
+ControlFlowInFinally()
+  : super(
+      name: LintNames.control_flow_in_finally,
+      description: r'Avoid control flow in `finally` blocks.',
+    );
+```
+
+### Incompatible rules
+
+A set of lint rules that the lint is incompatible with.
+
+If a lint rule has any incompatible rules,
+they can be specified by overriding the `incompatibleRules` getter
+and returning a list of incompatible lint names.
+
+```dart
+class UnnecessaryFinal extends LintRule {
+  // ...
+
+  @override
+  List<String> get incompatibleRules => const [
+        LintNames.prefer_final_locals,
+        LintNames.prefer_final_parameters,
+        LintNames.prefer_final_in_for_each,
+      ];
+}
+```
+
+### State
+
+A state indicating the lint's maturity and initial SDK version of that maturity.
+For details about the different lint states, check out [Lint lifecycle][].
+
+Lint states are defined in the lint's entry in the [`messages.yaml`][] file
+as well as in the lint's super constructor call.
+
+In the implementation file, only the most recent state is specified:
+
+```dart
+PackageApiDocs()
+  : super(
+      name: LintNames.package_api_docs,
+      description: _desc,
+      state: State.removed(since: Version(3, 7, 0)),
+    );
+```
+
+In the `messages.yaml` file, all historical states should be included,
+in order from oldest to most recent:
+
+```yaml
+package_api_docs:
+  # ...
+  state:
+    stable: "2.0"
+    deprecated: "3.6"
+    removed: "3.7"
+```
+
+[Lint lifecycle]: ./lint-lifecycle.md
+
+### Rationale
+
+In addition to the short description, a lint rule should have a
+more detailed rationale with code examples, ideally *good* and *bad*.
+
+[Effective Dart][] and the [existing lints][lints] are
+a great source for inspiration and formatting guidelines.
+
+The rationale docs are specified under the `deprecatedDetails` key
+in the lint's entry in the [`messages.yaml`][] file:
+
+```yaml
+control_flow_in_finally:
+  # ...
+  deprecatedDetails: |-
+    **AVOID** control flow leaving `finally` blocks.
+
+    ...Continued docs, bad examples, good examples...
+```
+
+[Effective Dart]: https://dart.dev/effective-dart
+[lints]: https://dart.dev/lints
+
+### Categories
+
+A set of relevant categories that developers can use to
+discover new lints to enable in their projects.
+
+The current available categories include:
+
+* `binarySize` - rules that help to minimize binary size.
+* `brevity` - rules that encourage brevity in the source code.
+* `documentationCommentMaintenance` - rules that help to maintain
+  documentation comments.
+* `effectiveDart` - rules that align with the Effective Dart style guide.
+* `errorProne` - rules that protect against error-prone code.
+* `flutter` - rules that help to write Flutter code.
+* `languageFeatureUsage` - rules that promote language feature usage.
+* `memoryLeaks` - rules that protect against possibly memory-leaking code.
+* `nonPerformant` - rules that protect against non-performant code.
+* `pub` - pub or package related rules.
+* `publicInterface` - rules that promote a healthy public interface.
+* `style` - matters of style, largely derived from Effective Dart.
+* `unintentional` - rules that protect against code that probably doesn't do
+  what you think it does, or that shouldn't be used as it is.
+* `unusedCode` - rules that protect against unused code.
+* `web` - rules that help to write code deployed to the web.
+
+The categories of a lint are specified in the
+lint's entry in the [`messages.yaml`][] file:
+
+```yaml
+avoid_web_libraries_in_flutter:
+  # ...
+  categories: [errorProne, flutter, web]
+```
+
+### Diagnostic documentation
+
+A longer set of documentation to help developers understand and resolve
+a diagnostic triggered by a lint rule.
+
+Diagnostic documentation for a lint includes a description about
+when the analyzer might report it, one or more examples that trigger it,
+as well as common fixes (generally corresponding to the examples).
+
+Diagnostic documentation is not yet mandatory for
+writing or publishing a lint rule.
+However, if you'd like to write diagnostic documentation,
+reference the analyzer contribution docs on [documenting diagnostics][].
+
+Diagnostic docs are defined in the lint's entry in the [`messages.yaml`][] file
+as the `documentation` key in a multi-line Markdown format:
+
+```yaml
+control_flow_in_finally:
+  # ...
+  documentation: |-
+    #### Description
+    ...
+    #### Example
+    ...
+    #### Common fixes
+    ...
+```
+
+If you do add or change a lint's diagnostic documentation,
+make sure to regenerate the resulting [`diagnostics.md` file][]:
+
+```
+dart run pkg/analyzer/tool/diagnostics/generate.dart
+```
+
+[documenting diagnostics]: ../../analyzer/doc/implementation/diagnostics.md#document-the-diagnostic
+[`diagnostics.md` file]: ../../analyzer/tool/diagnostics/diagnostics.md
 
 ## Mechanics
 
-Lints live in the [lib/src/rules] directory. Corresponding unit tests live in
-[test/rules]. 
+Lints live in the [`lib/src/rules`][] directory.
+Corresponding unit tests live in the [`test/rules`][] directory.
+Lint details and generation configuration live in the [`messages.yaml`][] file.
 
-Rule stubs can be generated with the [rule.dart] helper script:
+[`lib/src/rules`]: ../lib/src/rules
+[`test/rules`]: ../test/rules
+[`messages.yaml`]: ../messages.yaml
 
-    $ dart tool/rule.dart -n my_new_lint
-    
-generates lint and test stubs in `lib/src/rules` and `test/rules`.
+### Adding a lint
 
-### Analyzer APIs
+To add a lint, roughly follow these steps:
 
-The linter has a close relationship with the `analyzer` package and at times
-reaches into non-public APIs.  For the most part, we have isolated these
-references in an [analyzer.dart utility library].  *Wherever possible please
-use this library to access analyzer internals.*  
+1. Add at least one [lint code](#lint-codes) to the [`messages.yaml`][] file,
+   specifying at least the `correctionMessage` and `problemMessage` fields.
+1. Run `dart run pkg/linter/tool/generate_lints.dart` to generate the
+   `LintNames` and `LinterLintCode` static accessors.
+1. Create a Dart file with the same name as the lint in
+   the [`lib/src/rules`][] directory.
+1. Create a new class in the Dart file that extends `LintRule`,
+   calls the super constructor, and at least overrides the
+   `lintCodes` getter and the `registerNodeProcessors` method.
+1. Instantiate and register your created rule's class
+   in the [`lib/src/rules.dart`][] file.
+1. Reference other lint implementations in the [`lib/src/rules`][] directory
+   for guidelines on implementing the new lint.
 
-  * If `analyzer.dart` is missing something please consider opening an issue
-    where we can discuss how best to add it. 
+   **Note** that `'package:analyzer/dart/element/element2.dart'` should
+   be used instead of `'package:analyzer/dart/element/element.dart'`.
+1. Corresponding tests for the rule should live in a file with the same name,
+   but with a `_test` suffix, in the [`test/rules`][] directory.
+   For example: `test/rules/control_flow_in_finally_test.dart`.
+   For help writing tests, check out the [analyzer's test docs][] and
+   reference the reflective tests of other lints.
+1. Call your new tests in the [`test/rules/all.dart`][] file.
+1. Add the lint name in alphabetical order to the [`example/all.yaml`][] file.
+1. Finish the docs and details in the [`messages.yaml`][] file
+   and [regenerate the resulting documentation](#generating-docs) files.
+
+[`lib/src/rules.dart`]: ../lib/src/rules.dart
+[`test/rules/all.dart`]: ../test/rules/all.dart
+[`example/all.yaml`]: ../example/all.yaml
+[analyzer's test docs]: ../../analyzer/doc/implementation/tests.md
+
+### Internal analyzer APIs
+
+The linter has a close relationship with the `analyzer` package and
+at times reaches into non-public APIs.
+
+For the most part, we have isolated these references in
+an [`analyzer.dart` utility library][analyzer-imports].
+_Wherever possible please use this library to access analyzer internals._
+
+  * If `analyzer.dart` is missing something please consider
+    [opening an issue][issues] where we can discuss how best to add it.
   * If you find yourself tempted to make references to analyzer
-    [implementation classes][implementation_imports] also consider opening an
-    issue so that we can see how best to manage the new dependency.
-  
+    [implementation classes][implementation_imports] also consider
+    [opening an issue][issues] so that we can see how best to
+    manage the new dependency.
+
 Thanks!
 
-### Dart Language Specification
+[analyzer-imports]: https://github.com/dart-lang/linter/blob/main/lib/src/analyzer.dart
+[implementation_imports]: https://dart.dev/lints/implementation_imports
 
-When writing lints, it can be useful to have the [Dart Language Specification]
-handy.  If you're working to support bleeding edge language features, you'll
-want the [latest draft][draft language spec]. 
+### Dart language specification
 
-### Writing Tests that Depend on Dart SDK Details
+When writing lints, it can be useful to have the
+[Dart language specification][] handy.
+If you're working to support bleeding edge language features,
+you'll want to reference the [latest draft][draft language spec].
 
-**Important:** when writing tests that use standard `dart:` libraries, it's
-important to keep in mind that linter tests use a mocked SDK that has only a
-small subset of the real one.  We do this for performance reasons as it's FAR
-faster to load a mock SDK into memory than read the real one from disk.  If you
-are writing tests that depend on something in the Dart SDK (for example, an
-interface such as `Iterable`), you may need to update SDK mock content located
+In-progress or recently implemented feature specifications can
+often be found in the [`/working`][] and [`/accepted`][] directories of
+the [`dart-lang/language`][] repository instead.
+
+[Dart Language Specification]: https://dart.dev/guides/language/spec
+[draft language spec]: https://spec.dart.dev/DartLangSpecDraft.pdf
+[`/working`]: https://github.com/dart-lang/language/tree/main/working
+[`/accepted`]: https://github.com/dart-lang/language/tree/main/accepted
+[`dart-lang/language`]: https://github.com/dart-lang/language
+
+### Writing tests that depend on Dart SDK details
+
+**Important:** when writing tests that use standard `dart:` libraries,
+it's important to keep in mind that linter tests use a mocked SDK that
+only has a small subset of the real one.
+
+We do this for performance reasons as it's FAR
+faster to load a mock SDK into memory than read the real one from disk.
+If you are writing tests that depend on something in the Dart SDK
+(for example, an interface such as `Iterable`),
+you might need to update SDK mock content located
 in the `package:analyzer` [test utilities `mock_sdk.dart`][mock_sdk.dart].
 
-### Running Tests
+[mock_sdk.dart]: https://github.com/dart-lang/sdk/blob/main/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
 
-The test suite run during the linter's CI, can be run locally like so:
+### Running tests
 
-    $ dart test/all.dart
+The test suite run on the linter can be run locally like so:
+
+```
+dart run pkg/linter/test/all.dart
+```
+
+Changes to the linter can also affect tests in
+`pkg/analyzer` and `pkg/analysis_server`.
+All of their tests can be run as follows:
+
+```
+dart run pkg/analyzer/test/test_all.dart
+dart run pkg/analysis_server/test/test_all.dart
+```
+
+### Generating docs
+
+After modifying a lint rule's super constructor information
+or details in the [`messages.yaml`][] file,
+make sure all generated files are up to date.
+
+```
+dart run pkg/linter/tool/generate_lints.dart
+dart run pkg/analyzer/tool/diagnostics/generate.dart
+```
 
 ### Utilities
 
-You'll notice when authoring a new rule that failures cause the AST of the test
-case to be displayed to `stdout`.  If you simply want to dump the AST of a given
-compilation unit, you can use the `spelunk` helper directly.  For example:
+You'll notice when authoring a new rule that failures cause
+the AST of the test case to be displayed to `stdout`.
+If you simply want to dump the AST of a given compilation unit,
+you can use the `spelunk` helper directly.
 
-    $ dart tool/spelunk.dart lib/src/rules.dart
-    
-would dump the AST of `rules.dart`.
+For example, the following command dumps the AST of `rules.dart`:
+
+```
+dart run pkg/linter/tool/spelunk.dart pkg/linter/lib/src/rules.dart
+```
 
 ### Performance
 
-For performance reasons rules should prefer implementing `NodeLintRule` and
-registering interest in specific AST node types using
-`registry.addXYZ(this, visitor)`.  Avoid overriding `visitCompilationUnit()` and
+For performance reasons, rules should prefer
+implementing `NodeLintRule` and registering interest in
+specific AST node types using `registry.addXYZ(this, visitor)`.
+
+Avoid overriding `visitCompilationUnit()` and
 performing your own full `CompilationUnit` visits.
 
-# Feedback is Welcome!
+# Feedback is welcome!
 
-Details are under active development.  Feedback is most [welcome][issues]!
+Details are under active development.
+Feedback is most [welcome][issues]!
 
-[adding new checks to errorprone]: https://github.com/google/error-prone/wiki/Criteria-for-new-checks
-[Dart package naming conventions]: https://dart.dev/tools/pub/pubspec#name
-[parallel construction]: https://en.wikipedia.org/wiki/Parallelism_(grammar)
-[style guide]: https://dart.dev/effective-dart/style/
-[lints]: https://dart.dev/lints
-[lib/src/rules]: https://github.com/dart-lang/linter/tree/main/lib/src/rules
-[test_data/rules]: https://github.com/dart-lang/linter/tree/main/test_data/rules
-[rule.dart]: https://github.com/dart-lang/linter/blob/main/tool/rule.dart
-[analyzer.dart utility library]: https://github.com/dart-lang/linter/blob/main/lib/src/analyzer.dart
-[implementation_imports]: https://dart.dev/lints/implementation_imports
-[Dart Language Specification]: https://dart.dev/guides/language/spec
-[draft language spec]: https://spec.dart.dev/DartLangSpecDraft.pdf
-[mock_sdk.dart]: https://github.com/dart-lang/sdk/blob/main/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
-[issues]: https://github.com/dart-lang/linter/issues
+[issues]: https://github.com/dart-lang/sdk/issues/new?assignees=&labels=area-analyzer,analyzer-linter&projects=&template=2_analyzer.md