Adds a way to limits reference search by StructLiteral

This commit is contained in:
Mikhail Modin 2020-01-03 15:30:45 +00:00 committed by Aleksey Kladov
parent 5d8f2bd822
commit fb25c91979
3 changed files with 100 additions and 18 deletions

View file

@ -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#"

View file

@ -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() {

View file

@ -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(),
)) ))
} }