Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/references.rs')
-rw-r--r--crates/ide/src/references.rs92
1 files changed, 89 insertions, 3 deletions
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 4fa116444b..c6a323d408 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -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,
@@ -143,7 +200,7 @@ pub(crate) fn find_defs(
)
})?;
- if let Some((_, resolution)) = sema.check_for_format_args_template(token.clone(), offset) {
+ if let Some((.., resolution)) = sema.check_for_format_args_template(token.clone(), offset) {
return resolution.map(Definition::from).map(|it| vec![it]);
}
@@ -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! {