references_and_resolve.md: Cleanup

This commit is contained in:
Karol Lewandowski 2024-12-17 13:41:42 +01:00
parent f4fd8aed48
commit 16e10c0494

View File

@ -2,12 +2,12 @@
# References and Resolve # References and Resolve
<link-summary>PSI references allow for resolving from a symbol usage to its declaration.</link-summary> <link-summary>A PSI reference allows for resolving from a symbol usage to its declaration.</link-summary>
One of the most important and tricky parts in implementing a custom language PSI is resolving references. One of the most important and tricky parts in implementing a custom language PSI is resolving references.
Resolving references gives users the ability to navigate from a PSI element usage (accessing a variable, calling a method, etc.) to the declaration of that element (the variable's definition, a method declaration, and so on). Resolving references allows users to navigate from a PSI element usage (accessing a variable, calling a method, etc.) to the declaration of that element (the variable's definition, a method declaration, and so on).
This feature is needed in order to support the <ui-path>Navigate | Declaration or Usages</ui-path> action invoked by <shortcut>Ctrl/Cmd+B</shortcut> or clicking the mouse button while holding <shortcut>Ctrl/Cmd</shortcut> key, and it is a prerequisite for implementing the [Find Usages](find_usages.md) action, the [Rename Refactoring](rename_refactoring.md) and [Code Completion](code_completion.md). This feature is required to support the <ui-path>Navigate | Declaration or Usages</ui-path> action invoked by <shortcut>Ctrl/Cmd+B</shortcut> or clicking the mouse button while holding <shortcut>Ctrl/Cmd</shortcut> key, and it is a prerequisite for implementing [finding usages](find_usages.md), [rename refactoring](rename_refactoring.md), and [code completion](code_completion.md).
The <ui-path>View | Quick Definition</ui-path> action is based on the same mechanism, so it becomes automatically available for all references that can be resolved by the language plugin. The <ui-path>View | Quick Definition</ui-path> action is based on the same mechanism, so it becomes automatically available for all references that can be resolved by the language plugin.
To customize the exact document range to show in the popup (e.g., include "surrounding" code or comments), provide [`ImplementationTextSelectioner`](%gh-ic%/platform/lang-api/src/com/intellij/codeInsight/hint/ImplementationTextSelectioner.java) registered in `com.intellij.lang.implementationTextSelectioner` extension point. To customize the exact document range to show in the popup (e.g., include "surrounding" code or comments), provide [`ImplementationTextSelectioner`](%gh-ic%/platform/lang-api/src/com/intellij/codeInsight/hint/ImplementationTextSelectioner.java) registered in `com.intellij.lang.implementationTextSelectioner` extension point.
@ -17,12 +17,13 @@ To customize the exact document range to show in the popup (e.g., include "surro
All PSI elements which work as references (for which the <ui-path>Navigate | Declaration or Usages</ui-path> action applies) need to implement the All PSI elements which work as references (for which the <ui-path>Navigate | Declaration or Usages</ui-path> action applies) need to implement the
[`PsiElement.getReference()`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiElement.java) method and to return a [`PsiReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiReference.java) implementation from that method. [`PsiElement.getReference()`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiElement.java) method and to return a [`PsiReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiReference.java) implementation from that method.
The `PsiReference` can be implemented by the same class as `PsiElement`, or by a different class. The `PsiReference` can be implemented by the same class as `PsiElement`, or by a different class.
An element can also contain multiple references (for example, a string literal can contain multiple substrings which are valid fully-qualified class names), in which case it can implement `PsiElement.getReferences()` and return the references as an array. An element can also contain multiple references (for example, a string literal can contain multiple substrings which are valid fully qualified class names), in which case it can implement `PsiElement.getReferences()` and return the references as an array.
To optimize `PsiElement.getReferences()` performance, consider implementing [`HintedReferenceHost`](%gh-ic%/platform/core-api/src/com/intellij/psi/HintedReferenceHost.java) to provide additional hints. To optimize `PsiElement.getReferences()` performance, consider implementing [`HintedReferenceHost`](%gh-ic%/platform/core-api/src/com/intellij/psi/HintedReferenceHost.java) to provide additional hints.
The primary method of the [`PsiReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiReference.java) interface is `resolve()`, which returns the element to which the reference points, or `null` if it was not possible to resolve the reference to a valid element (for example, should it point to an undefined class). The primary method of the [`PsiReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiReference.java) interface is `resolve()`.
It returns the element to which the reference points, or `null` if it was not possible to resolve the reference to a valid element (for example, should it point to an undefined class).
The resolved element should implement the [`PsiNamedElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiNamedElement.java) interface. The resolved element should implement the [`PsiNamedElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiNamedElement.java) interface.
In order to enable more advanced functionality, prefer implementing [`PsiNameIdentifierOwner`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiNameIdentifierOwner.java) over [`PsiNamedElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiNamedElement.java) where possible. To enable more advanced functionality, prefer implementing [`PsiNameIdentifierOwner`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiNameIdentifierOwner.java) over [`PsiNamedElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiNamedElement.java) where possible.
> While the referencing element and the referenced element both may have a name, only the element which **introduces** the name (e.g., the definition `int x = 42`) needs to implement `PsiNamedElement`. > While the referencing element and the referenced element both may have a name, only the element which **introduces** the name (e.g., the definition `int x = 42`) needs to implement `PsiNamedElement`.
> The referencing element at the point of usage (e.g., the `x` in the expression `x + 1`) should not implement `PsiNamedElement` since it does not _have_ a name. > The referencing element at the point of usage (e.g., the `x` in the expression `x + 1`) should not implement `PsiNamedElement` since it does not _have_ a name.
@ -45,7 +46,7 @@ These interfaces have several extra complexities that are unnecessary for most c
Still, they are required if the custom language can have references to Java code. Still, they are required if the custom language can have references to Java code.
If Java interoperability is not required, the plugin can forgo the standard interfaces and provide its own, different implementation of resolve. If Java interoperability is not required, the plugin can forgo the standard interfaces and provide its own, different implementation of resolve.
Please see also [](psi_performance.md#cache-results-of-heavy-computations). See also [](psi_performance.md#cache-results-of-heavy-computations).
The implementation of resolve based on the standard helper classes contains the following components: The implementation of resolve based on the standard helper classes contains the following components:
@ -63,7 +64,7 @@ The implementation of resolve based on the standard helper classes contains the
## Resolving to Multiple Targets ## Resolving to Multiple Targets
An extension of the [`PsiReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiReference.java) interface, which allows a reference to resolve to multiple targets, is the [`PsiPolyVariantReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiPolyVariantReference.java) interface. [`PsiPolyVariantReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiPolyVariantReference.java) is an extension of [`PsiReference`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiReference.java) and allows a reference to resolve to multiple targets.
The targets to which the reference resolves are returned from the `multiResolve()` method. The targets to which the reference resolves are returned from the `multiResolve()` method.
The <ui-path>Navigate | Declaration or Usages</ui-path> action for such references allows the user to choose a navigation target in a popup. The <ui-path>Navigate | Declaration or Usages</ui-path> action for such references allows the user to choose a navigation target in a popup.
The implementation of `multiResolve()` can be also based on [`PsiScopeProcessor`](%gh-ic%/platform/core-api/src/com/intellij/psi/scope/PsiScopeProcessor.java), and can collect all valid targets for the reference instead of stopping when the first valid target is found. The implementation of `multiResolve()` can be also based on [`PsiScopeProcessor`](%gh-ic%/platform/core-api/src/com/intellij/psi/scope/PsiScopeProcessor.java), and can collect all valid targets for the reference instead of stopping when the first valid target is found.