aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/references.rs
diff options
context:
space:
mode:
authorEkaterina Babshukova <[email protected]>2019-09-14 12:38:10 +0100
committerEkaterina Babshukova <[email protected]>2019-10-22 21:47:31 +0100
commit11577288c23b1f2de1aaba0137c9c2d6344b9a92 (patch)
tree14b7da3cf3688fccc5994596fd21454896b3b0da /crates/ra_ide_api/src/references.rs
parentc15ee97fff4324981d03f65210d794664c28f0e4 (diff)
initial classify_name
Diffstat (limited to 'crates/ra_ide_api/src/references.rs')
-rw-r--r--crates/ra_ide_api/src/references.rs154
1 files changed, 126 insertions, 28 deletions
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 4247c6d90..9335bc8ca 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -1,13 +1,18 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Either, ModuleSource}; 3use hir::{FromSource, ModuleSource};
4use ra_db::{SourceDatabase, SourceDatabaseExt}; 4use ra_db::{SourceDatabase, SourceDatabaseExt};
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode}; 5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, AstPtr, SyntaxNode};
6use relative_path::{RelativePath, RelativePathBuf}; 6use relative_path::{RelativePath, RelativePathBuf};
7 7
8use crate::{ 8use crate::{
9 db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, 9 db::RootDatabase,
10 SourceChange, SourceFileEdit, TextRange, 10 name_ref_kind::{
11 classify_name_ref,
12 NameKind::{self, *},
13 },
14 FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, SourceChange,
15 SourceFileEdit, TextRange,
11}; 16};
12 17
13#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
@@ -52,41 +57,92 @@ pub(crate) fn find_all_refs(
52 position: FilePosition, 57 position: FilePosition,
53) -> Option<RangeInfo<ReferenceSearchResult>> { 58) -> Option<RangeInfo<ReferenceSearchResult>> {
54 let parse = db.parse(position.file_id); 59 let parse = db.parse(position.file_id);
55 let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?; 60 let syntax = parse.tree().syntax().clone();
56 let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); 61 let RangeInfo { range, info: (analyzer, name_kind) } = find_name(db, &syntax, position)?;
62
63 let declaration = match name_kind {
64 Macro(mac) => NavigationTarget::from_macro_def(db, mac),
65 FieldAccess(field) => NavigationTarget::from_field(db, field),
66 AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc),
67 Method(func) => NavigationTarget::from_def_source(db, func),
68 Def(def) => NavigationTarget::from_def(db, def)?,
69 SelfType(ref ty) => match ty.as_adt() {
70 Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id),
71 None => return None,
72 },
73 Pat(pat) => NavigationTarget::from_pat(db, position.file_id, pat),
74 SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par),
75 GenericParam(_) => return None,
76 };
57 77
58 let references = analyzer 78 let references = match name_kind {
59 .find_all_refs(&binding) 79 Pat(pat) => analyzer
60 .into_iter() 80 .find_all_refs(&pat.to_node(&syntax))
61 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) 81 .into_iter()
62 .collect::<Vec<_>>(); 82 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
83 .collect::<Vec<_>>(),
84 _ => vec![],
85 };
63 86
64 return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); 87 return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }));
65 88
66 fn find_binding<'a>( 89 fn find_name<'a>(
67 db: &RootDatabase, 90 db: &RootDatabase,
68 source_file: &SourceFile, 91 syntax: &SyntaxNode,
69 position: FilePosition, 92 position: FilePosition,
70 ) -> Option<RangeInfo<(ast::BindPat, hir::SourceAnalyzer)>> { 93 ) -> Option<RangeInfo<(hir::SourceAnalyzer, NameKind)>> {
71 let syntax = source_file.syntax(); 94 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) {
72 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { 95 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name.syntax(), None);
73 let range = binding.syntax().text_range(); 96 let name_kind = classify_name(db, position.file_id, &name)?;
74 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); 97 let range = name.syntax().text_range();
75 return Some(RangeInfo::new(range, (binding, analyzer))); 98 return Some(RangeInfo::new(range, (analyzer, name_kind)));
76 }; 99 }
77 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; 100 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?;
78 let range = name_ref.syntax().text_range(); 101 let range = name_ref.syntax().text_range();
79 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); 102 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
80 let resolved = analyzer.resolve_local_name(&name_ref)?; 103 let name_kind = classify_name_ref(db, &analyzer, &name_ref)?;
81 if let Either::A(ptr) = resolved.ptr() { 104 Some(RangeInfo::new(range, (analyzer, name_kind)))
82 if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) {
83 return Some(RangeInfo::new(range, (binding, analyzer)));
84 }
85 }
86 None
87 } 105 }
88} 106}
89 107
108fn classify_name(db: &RootDatabase, file_id: FileId, name: &ast::Name) -> Option<NameKind> {
109 let parent = name.syntax().parent()?;
110 let file_id = file_id.into();
111
112 if let Some(pat) = ast::BindPat::cast(parent.clone()) {
113 return Some(Pat(AstPtr::new(&pat)));
114 }
115 if let Some(var) = ast::EnumVariant::cast(parent.clone()) {
116 let src = hir::Source { file_id, ast: var };
117 let var = hir::EnumVariant::from_source(db, src)?;
118 return Some(Def(var.into()));
119 }
120 if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) {
121 let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) };
122 let field = hir::StructField::from_source(db, src)?;
123 return Some(FieldAccess(field));
124 }
125 if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) {
126 let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) };
127 let field = hir::StructField::from_source(db, src)?;
128 return Some(FieldAccess(field));
129 }
130 if let Some(_) = parent.parent().and_then(ast::ItemList::cast) {
131 let ast = ast::ImplItem::cast(parent.clone())?;
132 let src = hir::Source { file_id, ast };
133 let item = hir::AssocItem::from_source(db, src)?;
134 return Some(AssocItem(item));
135 }
136 if let Some(item) = ast::ModuleItem::cast(parent.clone()) {
137 let src = hir::Source { file_id, ast: item };
138 let def = hir::ModuleDef::from_source(db, src)?;
139 return Some(Def(def));
140 }
141 // FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union
142
143 None
144}
145
90pub(crate) fn rename( 146pub(crate) fn rename(
91 db: &RootDatabase, 147 db: &RootDatabase,
92 position: FilePosition, 148 position: FilePosition,
@@ -249,6 +305,48 @@ mod tests {
249 assert_eq!(refs.len(), 2); 305 assert_eq!(refs.len(), 2);
250 } 306 }
251 307
308 #[test]
309 fn test_find_all_refs_field_name() {
310 let code = r#"
311 //- /lib.rs
312 struct Foo {
313 spam<|>: u32,
314 }
315 "#;
316
317 let refs = get_all_refs(code);
318 assert_eq!(refs.len(), 1);
319 }
320
321 #[test]
322 fn test_find_all_refs_impl_item_name() {
323 let code = r#"
324 //- /lib.rs
325 struct Foo;
326 impl Foo {
327 fn f<|>(&self) { }
328 }
329 "#;
330
331 let refs = get_all_refs(code);
332 assert_eq!(refs.len(), 1);
333 }
334
335 #[test]
336 fn test_find_all_refs_enum_var_name() {
337 let code = r#"
338 //- /lib.rs
339 enum Foo {
340 A,
341 B<|>,
342 C,
343 }
344 "#;
345
346 let refs = get_all_refs(code);
347 assert_eq!(refs.len(), 1);
348 }
349
252 fn get_all_refs(text: &str) -> ReferenceSearchResult { 350 fn get_all_refs(text: &str) -> ReferenceSearchResult {
253 let (analysis, position) = single_file_with_position(text); 351 let (analysis, position) = single_file_with_position(text);
254 analysis.find_all_refs(position).unwrap().unwrap() 352 analysis.find_all_refs(position).unwrap().unwrap()