mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge #2738
2738: [Draft] Adds a way to limits reference search by StructLiteral r=matklad a=mikhail-m1 first draft for #2549 Co-authored-by: Mikhail Modin <mikhailm1@gmail.com>
This commit is contained in:
commit
928ecd069a
3 changed files with 100 additions and 18 deletions
|
@ -18,7 +18,10 @@ use hir::InFile;
|
|||
use once_cell::unsync::Lazy;
|
||||
use ra_db::{SourceDatabase, SourceDatabaseExt};
|
||||
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::{
|
||||
db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo,
|
||||
|
@ -35,7 +38,20 @@ pub use self::search_scope::SearchScope;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct ReferenceSearchResult {
|
||||
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 {
|
||||
|
@ -43,7 +59,7 @@ impl ReferenceSearchResult {
|
|||
&self.declaration
|
||||
}
|
||||
|
||||
pub fn references(&self) -> &[FileRange] {
|
||||
pub fn references(&self) -> &[Reference] {
|
||||
&self.references
|
||||
}
|
||||
|
||||
|
@ -58,12 +74,18 @@ impl ReferenceSearchResult {
|
|||
// allow turning ReferenceSearchResult into an iterator
|
||||
// over FileRanges
|
||||
impl IntoIterator for ReferenceSearchResult {
|
||||
type Item = FileRange;
|
||||
type IntoIter = std::vec::IntoIter<FileRange>;
|
||||
type Item = Reference;
|
||||
type IntoIter = std::vec::IntoIter<Reference>;
|
||||
|
||||
fn into_iter(mut self) -> Self::IntoIter {
|
||||
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.into_iter()
|
||||
}
|
||||
|
@ -71,11 +93,24 @@ impl IntoIterator for ReferenceSearchResult {
|
|||
|
||||
pub(crate) fn find_all_refs(
|
||||
db: &RootDatabase,
|
||||
position: FilePosition,
|
||||
mut position: FilePosition,
|
||||
search_scope: Option<SearchScope>,
|
||||
) -> Option<RangeInfo<ReferenceSearchResult>> {
|
||||
let parse = db.parse(position.file_id);
|
||||
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 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>(
|
||||
|
@ -122,7 +163,7 @@ fn process_definition(
|
|||
def: NameDefinition,
|
||||
name: String,
|
||||
scope: SearchScope,
|
||||
) -> Vec<FileRange> {
|
||||
) -> Vec<Reference> {
|
||||
let _p = profile("process_definition");
|
||||
|
||||
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 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,
|
||||
};
|
||||
|
||||
#[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]
|
||||
fn test_find_all_refs_for_local() {
|
||||
let code = r#"
|
||||
|
|
|
@ -110,7 +110,13 @@ fn rename_reference(
|
|||
|
||||
let edit = refs
|
||||
.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<_>>();
|
||||
|
||||
if edit.is_empty() {
|
||||
|
|
|
@ -531,8 +531,8 @@ pub fn handle_references(
|
|||
let locations = if params.context.include_declaration {
|
||||
refs.into_iter()
|
||||
.filter_map(|r| {
|
||||
let line_index = world.analysis().file_line_index(r.file_id).ok()?;
|
||||
to_location(r.file_id, r.range, &world, &line_index).ok()
|
||||
let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?;
|
||||
to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok()
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
|
@ -540,8 +540,8 @@ pub fn handle_references(
|
|||
refs.references()
|
||||
.iter()
|
||||
.filter_map(|r| {
|
||||
let line_index = world.analysis().file_line_index(r.file_id).ok()?;
|
||||
to_location(r.file_id, r.range, &world, &line_index).ok()
|
||||
let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?;
|
||||
to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok()
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
@ -830,8 +830,11 @@ pub fn handle_document_highlight(
|
|||
|
||||
Ok(Some(
|
||||
refs.into_iter()
|
||||
.filter(|r| r.file_id == file_id)
|
||||
.map(|r| DocumentHighlight { range: r.range.conv_with(&line_index), kind: None })
|
||||
.filter(|r| r.file_range.file_id == file_id)
|
||||
.map(|r| DocumentHighlight {
|
||||
range: r.file_range.range.conv_with(&line_index),
|
||||
kind: None,
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue