Merge pull request #19861 from vremyavnikuda/docs/find-all-refs-constructor-search
Some checks are pending
metrics / generate_final_metrics (push) Blocked by required conditions
metrics / build_metrics (push) Waiting to run
metrics / other_metrics (diesel-1.4.8) (push) Blocked by required conditions
metrics / other_metrics (hyper-0.14.18) (push) Blocked by required conditions
metrics / other_metrics (ripgrep-13.0.0) (push) Blocked by required conditions
metrics / other_metrics (self) (push) Blocked by required conditions
metrics / other_metrics (webrender-2022) (push) Blocked by required conditions
rustdoc / rustdoc (push) Waiting to run

docs: add documentation for find_all_refs constructor search
This commit is contained in:
Lukas Wirth 2025-05-30 06:45:28 +00:00 committed by GitHub
commit e65dddaf59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 88 additions and 3 deletions

View file

@ -514,7 +514,6 @@ impl Analysis {
self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
}
/// Finds all usages of the reference at point.
pub fn find_all_refs(
&self,
position: FilePosition,

View file

@ -8,6 +8,14 @@
//! for text occurrences of the identifier. If there's an `ast::NameRef`
//! at the index that the match starts at and its tree parent is
//! resolved to the search element definition, we get a reference.
//!
//! Special handling for constructors/initializations:
//! When searching for references to a struct/enum/variant, if the cursor is positioned on:
//! - `{` after a struct/enum/variant definition
//! - `(` for tuple structs/variants
//! - `;` for unit structs
//! - The type name in a struct/enum/variant definition
//! Then only constructor/initialization usages will be shown, filtering out other references.
use hir::{PathResolution, Semantics};
use ide_db::{
@ -28,27 +36,76 @@ use syntax::{
use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related};
/// Result of a reference search operation.
#[derive(Debug, Clone)]
pub struct ReferenceSearchResult {
/// Information about the declaration site of the searched item.
/// For ADTs (structs/enums), this points to the type definition.
/// May be None for primitives or items without clear declaration sites.
pub declaration: Option<Declaration>,
/// All references found, grouped by file.
/// For ADTs when searching from a constructor position (e.g. on '{', '(', ';'),
/// this only includes constructor/initialization usages.
/// The map key is the file ID, and the value is a vector of (range, category) pairs.
/// - range: The text range of the reference in the file
/// - category: Metadata about how the reference is used (read/write/etc)
pub references: IntMap<FileId, Vec<(TextRange, ReferenceCategory)>>,
}
/// Information about the declaration site of a searched item.
#[derive(Debug, Clone)]
pub struct Declaration {
/// Navigation information to jump to the declaration
pub nav: NavigationTarget,
/// Whether the declared item is mutable (relevant for variables)
pub is_mut: bool,
}
// Feature: Find All References
//
// Shows all references of the item at the cursor location
// Shows all references of the item at the cursor location. This includes:
// - Direct references to variables, functions, types, etc.
// - Constructor/initialization references when cursor is on struct/enum definition tokens
// - References in patterns and type contexts
// - References through dereferencing and borrowing
// - References in macro expansions
//
// Special handling for constructors:
// - When the cursor is on `{`, `(`, or `;` in a struct/enum definition
// - When the cursor is on the type name in a struct/enum definition
// These cases will show only constructor/initialization usages of the type
//
// | Editor | Shortcut |
// |---------|----------|
// | VS Code | <kbd>Shift+Alt+F12</kbd> |
//
// ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif)
/// Find all references to the item at the given position.
///
/// # Arguments
/// * `sema` - Semantic analysis context
/// * `position` - Position in the file where to look for the item
/// * `search_scope` - Optional scope to limit the search (e.g. current crate only)
///
/// # Returns
/// Returns `None` if no valid item is found at the position.
/// Otherwise returns a vector of `ReferenceSearchResult`, usually with one element.
/// Multiple results can occur in case of ambiguity or when searching for trait items.
///
/// # Special cases
/// - Control flow keywords (break, continue, etc): Shows all related jump points
/// - Constructor search: When on struct/enum definition tokens (`{`, `(`, `;`), shows only initialization sites
/// - Format string arguments: Shows template parameter usages
/// - Lifetime parameters: Shows lifetime constraint usages
///
/// # Constructor search
/// When the cursor is on specific tokens in a struct/enum definition:
/// - `{` after struct/enum/variant: Shows record literal initializations
/// - `(` after tuple struct/variant: Shows tuple literal initializations
/// - `;` after unit struct: Shows unit literal initializations
/// - Type name in definition: Shows all initialization usages
/// In these cases, other kinds of references (like type references) are filtered out.
pub(crate) fn find_all_refs(
sema: &Semantics<'_, RootDatabase>,
position: FilePosition,
@ -219,7 +276,19 @@ fn retain_adt_literal_usages(
}
}
/// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages
/// Returns `Some` if the cursor is at a position where we should search for constructor/initialization usages.
/// This is used to implement the special constructor search behavior when the cursor is on specific tokens
/// in a struct/enum/variant definition.
///
/// # Returns
/// - `Some(name)` if the cursor is on:
/// - `{` after a struct/enum/variant definition
/// - `(` for tuple structs/variants
/// - `;` for unit structs
/// - The type name in a struct/enum/variant definition
/// - `None` otherwise
///
/// The returned name is the name of the type whose constructor usages should be searched for.
fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> {
let token = syntax.token_at_offset(position.offset).right_biased()?;
let token_parent = token.parent()?;
@ -257,6 +326,16 @@ fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> O
}
}
/// Checks if a name reference is part of an enum variant literal expression.
/// Used to filter references when searching for enum variant constructors.
///
/// # Arguments
/// * `sema` - Semantic analysis context
/// * `enum_` - The enum type to check against
/// * `name_ref` - The name reference to check
///
/// # Returns
/// `true` if the name reference is used as part of constructing a variant of the given enum.
fn is_enum_lit_name_ref(
sema: &Semantics<'_, RootDatabase>,
enum_: hir::Enum,
@ -284,12 +363,19 @@ fn is_enum_lit_name_ref(
.unwrap_or(false)
}
/// Checks if a path ends with the given name reference.
/// Helper function for checking constructor usage patterns.
fn path_ends_with(path: Option<ast::Path>, name_ref: &ast::NameRef) -> bool {
path.and_then(|path| path.segment())
.and_then(|segment| segment.name_ref())
.map_or(false, |segment| segment == *name_ref)
}
/// Checks if a name reference is used in a literal (constructor) context.
/// Used to filter references when searching for struct/variant constructors.
///
/// # Returns
/// `true` if the name reference is used as part of a struct/variant literal expression.
fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
name_ref.syntax().ancestors().find_map(|ancestor| {
match_ast! {