mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
Adds a way to limits reference search by StructLiteral
This commit is contained in:
parent
5d8f2bd822
commit
fb25c91979
3 changed files with 100 additions and 18 deletions
|
@ -18,7 +18,10 @@ use hir::InFile;
|
||||||
use once_cell::unsync::Lazy;
|
use once_cell::unsync::Lazy;
|
||||||
use ra_db::{SourceDatabase, SourceDatabaseExt};
|
use ra_db::{SourceDatabase, SourceDatabaseExt};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit};
|
use ra_syntax::{
|
||||||
|
algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextUnit,
|
||||||
|
TokenAtOffset,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo,
|
db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo,
|
||||||
|
@ -35,7 +38,20 @@ pub use self::search_scope::SearchScope;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReferenceSearchResult {
|
pub struct ReferenceSearchResult {
|
||||||
declaration: NavigationTarget,
|
declaration: NavigationTarget,
|
||||||
references: Vec<FileRange>,
|
declaration_kind: ReferenceKind,
|
||||||
|
references: Vec<Reference>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Reference {
|
||||||
|
pub file_range: FileRange,
|
||||||
|
pub kind: ReferenceKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum ReferenceKind {
|
||||||
|
StructLiteral,
|
||||||
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReferenceSearchResult {
|
impl ReferenceSearchResult {
|
||||||
|
@ -43,7 +59,7 @@ impl ReferenceSearchResult {
|
||||||
&self.declaration
|
&self.declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn references(&self) -> &[FileRange] {
|
pub fn references(&self) -> &[Reference] {
|
||||||
&self.references
|
&self.references
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,12 +74,18 @@ impl ReferenceSearchResult {
|
||||||
// allow turning ReferenceSearchResult into an iterator
|
// allow turning ReferenceSearchResult into an iterator
|
||||||
// over FileRanges
|
// over FileRanges
|
||||||
impl IntoIterator for ReferenceSearchResult {
|
impl IntoIterator for ReferenceSearchResult {
|
||||||
type Item = FileRange;
|
type Item = Reference;
|
||||||
type IntoIter = std::vec::IntoIter<FileRange>;
|
type IntoIter = std::vec::IntoIter<Reference>;
|
||||||
|
|
||||||
fn into_iter(mut self) -> Self::IntoIter {
|
fn into_iter(mut self) -> Self::IntoIter {
|
||||||
let mut v = Vec::with_capacity(self.len());
|
let mut v = Vec::with_capacity(self.len());
|
||||||
v.push(FileRange { file_id: self.declaration.file_id(), range: self.declaration.range() });
|
v.push(Reference {
|
||||||
|
file_range: FileRange {
|
||||||
|
file_id: self.declaration.file_id(),
|
||||||
|
range: self.declaration.range(),
|
||||||
|
},
|
||||||
|
kind: self.declaration_kind,
|
||||||
|
});
|
||||||
v.append(&mut self.references);
|
v.append(&mut self.references);
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
}
|
}
|
||||||
|
@ -71,11 +93,24 @@ impl IntoIterator for ReferenceSearchResult {
|
||||||
|
|
||||||
pub(crate) fn find_all_refs(
|
pub(crate) fn find_all_refs(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
position: FilePosition,
|
mut position: FilePosition,
|
||||||
search_scope: Option<SearchScope>,
|
search_scope: Option<SearchScope>,
|
||||||
) -> Option<RangeInfo<ReferenceSearchResult>> {
|
) -> Option<RangeInfo<ReferenceSearchResult>> {
|
||||||
let parse = db.parse(position.file_id);
|
let parse = db.parse(position.file_id);
|
||||||
let syntax = parse.tree().syntax().clone();
|
let syntax = parse.tree().syntax().clone();
|
||||||
|
|
||||||
|
let token = syntax.token_at_offset(position.offset);
|
||||||
|
let mut search_kind = ReferenceKind::Other;
|
||||||
|
|
||||||
|
if let TokenAtOffset::Between(ref left, ref right) = token {
|
||||||
|
if (right.kind() == SyntaxKind::L_CURLY || right.kind() == SyntaxKind::L_PAREN)
|
||||||
|
&& left.kind() != SyntaxKind::IDENT
|
||||||
|
{
|
||||||
|
position = FilePosition { offset: left.text_range().start(), ..position };
|
||||||
|
search_kind = ReferenceKind::StructLiteral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?;
|
let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?;
|
||||||
|
|
||||||
let declaration = match def.kind {
|
let declaration = match def.kind {
|
||||||
|
@ -96,9 +131,15 @@ pub(crate) fn find_all_refs(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let references = process_definition(db, def, name, search_scope);
|
let references = process_definition(db, def, name, search_scope)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
|
||||||
|
.collect();
|
||||||
|
|
||||||
Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }))
|
Some(RangeInfo::new(
|
||||||
|
range,
|
||||||
|
ReferenceSearchResult { declaration, references, declaration_kind: ReferenceKind::Other },
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_name<'a>(
|
fn find_name<'a>(
|
||||||
|
@ -122,7 +163,7 @@ fn process_definition(
|
||||||
def: NameDefinition,
|
def: NameDefinition,
|
||||||
name: String,
|
name: String,
|
||||||
scope: SearchScope,
|
scope: SearchScope,
|
||||||
) -> Vec<FileRange> {
|
) -> Vec<Reference> {
|
||||||
let _p = profile("process_definition");
|
let _p = profile("process_definition");
|
||||||
|
|
||||||
let pat = name.as_str();
|
let pat = name.as_str();
|
||||||
|
@ -146,7 +187,21 @@ fn process_definition(
|
||||||
}
|
}
|
||||||
if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) {
|
if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) {
|
||||||
if d == def {
|
if d == def {
|
||||||
refs.push(FileRange { file_id, range });
|
let kind = if name_ref
|
||||||
|
.syntax()
|
||||||
|
.ancestors()
|
||||||
|
.find_map(ast::RecordLit::cast)
|
||||||
|
.and_then(|l| l.path())
|
||||||
|
.and_then(|p| p.segment())
|
||||||
|
.and_then(|p| p.name_ref())
|
||||||
|
.map(|n| n == name_ref)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
ReferenceKind::StructLiteral
|
||||||
|
} else {
|
||||||
|
ReferenceKind::Other
|
||||||
|
};
|
||||||
|
refs.push(Reference { file_range: FileRange { file_id, range }, kind });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,6 +217,24 @@ mod tests {
|
||||||
ReferenceSearchResult, SearchScope,
|
ReferenceSearchResult, SearchScope,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_struct_literal() {
|
||||||
|
let code = r#"
|
||||||
|
struct Foo <|>{
|
||||||
|
a: i32,
|
||||||
|
}
|
||||||
|
impl Foo {
|
||||||
|
fn f() -> i32 { 42 }
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let f: Foo;
|
||||||
|
f = Foo {a: Foo::f()};
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let refs = get_all_refs(code);
|
||||||
|
assert_eq!(refs.len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_all_refs_for_local() {
|
fn test_find_all_refs_for_local() {
|
||||||
let code = r#"
|
let code = r#"
|
||||||
|
|
|
@ -110,7 +110,13 @@ fn rename_reference(
|
||||||
|
|
||||||
let edit = refs
|
let edit = refs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name))
|
.map(|reference| {
|
||||||
|
source_edit_from_file_id_range(
|
||||||
|
reference.file_range.file_id,
|
||||||
|
reference.file_range.range,
|
||||||
|
new_name,
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if edit.is_empty() {
|
if edit.is_empty() {
|
||||||
|
|
|
@ -531,8 +531,8 @@ pub fn handle_references(
|
||||||
let locations = if params.context.include_declaration {
|
let locations = if params.context.include_declaration {
|
||||||
refs.into_iter()
|
refs.into_iter()
|
||||||
.filter_map(|r| {
|
.filter_map(|r| {
|
||||||
let line_index = world.analysis().file_line_index(r.file_id).ok()?;
|
let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?;
|
||||||
to_location(r.file_id, r.range, &world, &line_index).ok()
|
to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
|
@ -540,8 +540,8 @@ pub fn handle_references(
|
||||||
refs.references()
|
refs.references()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|r| {
|
.filter_map(|r| {
|
||||||
let line_index = world.analysis().file_line_index(r.file_id).ok()?;
|
let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?;
|
||||||
to_location(r.file_id, r.range, &world, &line_index).ok()
|
to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
@ -830,8 +830,11 @@ pub fn handle_document_highlight(
|
||||||
|
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
refs.into_iter()
|
refs.into_iter()
|
||||||
.filter(|r| r.file_id == file_id)
|
.filter(|r| r.file_range.file_id == file_id)
|
||||||
.map(|r| DocumentHighlight { range: r.range.conv_with(&line_index), kind: None })
|
.map(|r| DocumentHighlight {
|
||||||
|
range: r.file_range.range.conv_with(&line_index),
|
||||||
|
kind: None,
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue