# Document highlight

   LSP:    [textDocument/documentHighlight][] requests
   Legacy: `analysis.occurrences` notification

Document highlight is used to highlight both local declarations of and
references to the element declared or referenced at the location of the
insertion cursor.

## Symmetry

In most cases the operation should be symmetric. That is, the same set of
locations should be highlighted no matter which of those locations contains the
insertion cursor. For example, if the user clicks on the declaration of a local
variable, then all references to that variable should be highlighted, and if the
user clicks on any of the highlighted references the set of highlights should
stay the same.

There are a few cases where symmetry is violated. In particular, symmetry is
violated at declaration sites where a single declaration introduces multiple
elements. In those cases, the set of references to all of the introduced
elements are highlighted, clicking on one of the highlighted references will
remove the highlights related to other elements.

Declarations are the only place where this can occur. Any other references are,
by the semantics of the language, a reference to a single element, so only
references to that element should be highlighted. This is in keeping with the
[principle of language fidelity][languageFidelity].

Below is a list of the places where symmetry is intentionally broken.

- The declaration of a field introduces both the field (a storage location in an
  object), a getter, and optionally a setter (unless the field is either `final'
  or `const`). Selecting the field should highlight references to all three
  elements; selecting a reference to one of those three elements should only
  highlight references to the same element.

- The declaration of a top-level variable similarly introduces both the variable
  (a storage location), a getter, and optionally a setter (unless the variable
  is either `final` or `const`).

- The declaration of a declaring parameter introduces both the parameter and a
  field, which in turn introduces a getter and a possible setter.

- In an object or record pattern, the names of a getter can be omitted if the
  matching pattern is a variable declaration pattern whose name matches the name
  of the getter. If the getter isn't specified, then the variable declaration
  introduces both a local variable declaration and a reference to the getter.

There are a couple of other places where one declaration introduces other
elements where we don't break symmetry. There isn't a principled reason for
this, but it seems like breaking symmetry in these cases would be more
surprising to users than the inconsistency is.

- The declaration of a class or enum, when that declaration doesn't have an
explicit declaration of a constructor, introduces the declaration of a default
constructor (an unnamed constructor with no parameters).

- The declaration of an enum introduces the static getter `values` and the
instance getters `index` and `name`.

## Kinds

Each document highlight has an associated `kind` which allows clients to
highlight reads and writes differently. The LSP spec says:

> Symbol matches usually have a `DocumentHighlightKind` of `Read` or `Write`
> whereas fuzzy or textual matches use `Text` as the kind.

TypeScript (which we often try to be consistent with when expected behaviour
isn't obvious, since the VS Code, LSP and TypeScript teams working closely
together) uses `Read` and `Write` even for names of types, so we have followed
that pattern.

- `Write` - assignments (setters, variables, initializers), declarations, argument names
- `Read` - getters, variable reads, references to types and parameters
- `Text` - keywords like `for`, `break`, `return`

[languageFidelity]: ../principles/language_fidelity.md
[textDocument/documentHighlight]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentHighlight
