Skip to content

Commit 44612c5

Browse files
committed
docs: add documentation for find_all_refs constructor search (#10725)
1 parent 94c624e commit 44612c5

File tree

2 files changed

+158
-3
lines changed

2 files changed

+158
-3
lines changed

src/tools/rust-analyzer/crates/ide/src/lib.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,76 @@ impl Analysis {
514514
self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
515515
}
516516

517-
/// Finds all usages of the reference at point.
517+
/// Find all references to the item at the cursor position.
518+
///
519+
/// # Examples
520+
///
521+
/// Basic struct reference search:
522+
/// ```rust
523+
/// struct S {
524+
/// pub x: usize,
525+
/// }
526+
///
527+
/// fn print_s(s: S) {
528+
/// println!("{}", s.x)
529+
/// }
530+
///
531+
/// fn main() {
532+
/// let s = S { x: 42 }; // This is a constructor usage
533+
/// print_s(s); // This is a type reference
534+
/// }
535+
/// ```
536+
///
537+
/// To find only constructor/initialization usages:
538+
/// 1. Position cursor on special tokens in struct/enum definition:
539+
/// ```rust
540+
/// // On '{' - finds record struct initializations
541+
/// struct Point { // <- cursor here on '{'
542+
/// x: i32,
543+
/// y: i32,
544+
/// }
545+
///
546+
/// // On '(' - finds tuple struct initializations
547+
/// struct Tuple(i32, i32); // <- cursor here on '('
548+
///
549+
/// // On ';' - finds unit struct initializations
550+
/// struct Unit; // <- cursor here on ';'
551+
/// ```
552+
///
553+
/// 2. Examples of what will be found:
554+
/// ```rust
555+
/// struct Point{x: i32, y: i32};
556+
/// struct Tuple(i32, i32);
557+
/// struct Unit;
558+
///
559+
///
560+
/// let p1 = Point { x: 0, y: 0 }; // Found when cursor on '{'
561+
/// let p2 = Tuple(1, 2); // Found when cursor on '('
562+
/// let u = Unit; // Found when cursor on ';'
563+
/// ```
564+
///
565+
/// 3. For enum variants:
566+
/// ```rust
567+
/// enum E {
568+
/// Struct { // <- cursor here on '{'
569+
/// x: i32
570+
/// },
571+
/// Tuple(i32), // <- cursor here on '('
572+
/// Unit // <- cursor here on identifier
573+
/// }
574+
///
575+
/// let e1 = E::Struct { x: 0 }; // Found for Struct variant
576+
/// let e2 = E::Tuple(1); // Found for Tuple variant
577+
/// let e3 = E::Unit; // Found for Unit variant
578+
/// ```
579+
///
580+
/// # Parameters
581+
/// * `position` - The position in the file to find references for
582+
/// * `search_scope` - Optional scope to limit the search
583+
///
584+
/// # Returns
585+
/// Returns a vector of reference search results if references are found,
586+
/// or None if no valid item is found at the position.
518587
pub fn find_all_refs(
519588
&self,
520589
position: FilePosition,

src/tools/rust-analyzer/crates/ide/src/references.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
//! for text occurrences of the identifier. If there's an `ast::NameRef`
99
//! at the index that the match starts at and its tree parent is
1010
//! resolved to the search element definition, we get a reference.
11+
//!
12+
//! Special handling for constructors/initializations:
13+
//! When searching for references to a struct/enum/variant, if the cursor is positioned on:
14+
//! - `{` after a struct/enum/variant definition
15+
//! - `(` for tuple structs/variants
16+
//! - `;` for unit structs
17+
//! - The type name in a struct/enum/variant definition
18+
//! Then only constructor/initialization usages will be shown, filtering out other references.
1119
1220
use hir::{PathResolution, Semantics};
1321
use ide_db::{
@@ -28,27 +36,76 @@ use syntax::{
2836

2937
use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related};
3038

39+
/// Result of a reference search operation.
3140
#[derive(Debug, Clone)]
3241
pub struct ReferenceSearchResult {
42+
/// Information about the declaration site of the searched item.
43+
/// For ADTs (structs/enums), this points to the type definition.
44+
/// May be None for primitives or items without clear declaration sites.
3345
pub declaration: Option<Declaration>,
46+
/// All references found, grouped by file.
47+
/// For ADTs when searching from a constructor position (e.g. on '{', '(', ';'),
48+
/// this only includes constructor/initialization usages.
49+
/// The map key is the file ID, and the value is a vector of (range, category) pairs.
50+
/// - range: The text range of the reference in the file
51+
/// - category: Metadata about how the reference is used (read/write/etc)
3452
pub references: IntMap<FileId, Vec<(TextRange, ReferenceCategory)>>,
3553
}
3654

55+
/// Information about the declaration site of a searched item.
3756
#[derive(Debug, Clone)]
3857
pub struct Declaration {
58+
/// Navigation information to jump to the declaration
3959
pub nav: NavigationTarget,
60+
/// Whether the declared item is mutable (relevant for variables)
4061
pub is_mut: bool,
4162
}
4263

4364
// Feature: Find All References
4465
//
45-
// Shows all references of the item at the cursor location
66+
// Shows all references of the item at the cursor location. This includes:
67+
// - Direct references to variables, functions, types, etc.
68+
// - Constructor/initialization references when cursor is on struct/enum definition tokens
69+
// - References in patterns and type contexts
70+
// - References through dereferencing and borrowing
71+
// - References in macro expansions
72+
//
73+
// Special handling for constructors:
74+
// - When the cursor is on `{`, `(`, or `;` in a struct/enum definition
75+
// - When the cursor is on the type name in a struct/enum definition
76+
// These cases will show only constructor/initialization usages of the type
4677
//
4778
// | Editor | Shortcut |
4879
// |---------|----------|
4980
// | VS Code | <kbd>Shift+Alt+F12</kbd> |
5081
//
5182
// ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif)
83+
84+
/// Find all references to the item at the given position.
85+
///
86+
/// # Arguments
87+
/// * `sema` - Semantic analysis context
88+
/// * `position` - Position in the file where to look for the item
89+
/// * `search_scope` - Optional scope to limit the search (e.g. current crate only)
90+
///
91+
/// # Returns
92+
/// Returns `None` if no valid item is found at the position.
93+
/// Otherwise returns a vector of `ReferenceSearchResult`, usually with one element.
94+
/// Multiple results can occur in case of ambiguity or when searching for trait items.
95+
///
96+
/// # Special cases
97+
/// - Control flow keywords (break, continue, etc): Shows all related jump points
98+
/// - Constructor search: When on struct/enum definition tokens (`{`, `(`, `;`), shows only initialization sites
99+
/// - Format string arguments: Shows template parameter usages
100+
/// - Lifetime parameters: Shows lifetime constraint usages
101+
///
102+
/// # Constructor search
103+
/// When the cursor is on specific tokens in a struct/enum definition:
104+
/// - `{` after struct/enum/variant: Shows record literal initializations
105+
/// - `(` after tuple struct/variant: Shows tuple literal initializations
106+
/// - `;` after unit struct: Shows unit literal initializations
107+
/// - Type name in definition: Shows all initialization usages
108+
/// In these cases, other kinds of references (like type references) are filtered out.
52109
pub(crate) fn find_all_refs(
53110
sema: &Semantics<'_, RootDatabase>,
54111
position: FilePosition,
@@ -219,7 +276,19 @@ fn retain_adt_literal_usages(
219276
}
220277
}
221278

222-
/// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages
279+
/// Returns `Some` if the cursor is at a position where we should search for constructor/initialization usages.
280+
/// This is used to implement the special constructor search behavior when the cursor is on specific tokens
281+
/// in a struct/enum/variant definition.
282+
///
283+
/// # Returns
284+
/// - `Some(name)` if the cursor is on:
285+
/// - `{` after a struct/enum/variant definition
286+
/// - `(` for tuple structs/variants
287+
/// - `;` for unit structs
288+
/// - The type name in a struct/enum/variant definition
289+
/// - `None` otherwise
290+
///
291+
/// The returned name is the name of the type whose constructor usages should be searched for.
223292
fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> {
224293
let token = syntax.token_at_offset(position.offset).right_biased()?;
225294
let token_parent = token.parent()?;
@@ -257,6 +326,16 @@ fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> O
257326
}
258327
}
259328

329+
/// Checks if a name reference is part of an enum variant literal expression.
330+
/// Used to filter references when searching for enum variant constructors.
331+
///
332+
/// # Arguments
333+
/// * `sema` - Semantic analysis context
334+
/// * `enum_` - The enum type to check against
335+
/// * `name_ref` - The name reference to check
336+
///
337+
/// # Returns
338+
/// `true` if the name reference is used as part of constructing a variant of the given enum.
260339
fn is_enum_lit_name_ref(
261340
sema: &Semantics<'_, RootDatabase>,
262341
enum_: hir::Enum,
@@ -284,12 +363,19 @@ fn is_enum_lit_name_ref(
284363
.unwrap_or(false)
285364
}
286365

366+
/// Checks if a path ends with the given name reference.
367+
/// Helper function for checking constructor usage patterns.
287368
fn path_ends_with(path: Option<ast::Path>, name_ref: &ast::NameRef) -> bool {
288369
path.and_then(|path| path.segment())
289370
.and_then(|segment| segment.name_ref())
290371
.map_or(false, |segment| segment == *name_ref)
291372
}
292373

374+
/// Checks if a name reference is used in a literal (constructor) context.
375+
/// Used to filter references when searching for struct/variant constructors.
376+
///
377+
/// # Returns
378+
/// `true` if the name reference is used as part of a struct/variant literal expression.
293379
fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
294380
name_ref.syntax().ancestors().find_map(|ancestor| {
295381
match_ast! {

0 commit comments

Comments
 (0)