aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/references.rs95
-rw-r--r--crates/ra_ide/src/references/rename.rs8
2 files changed, 91 insertions, 12 deletions
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index e3ecde50d..a0226b1bc 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -18,7 +18,10 @@ use hir::InFile;
18use once_cell::unsync::Lazy; 18use once_cell::unsync::Lazy;
19use ra_db::{SourceDatabase, SourceDatabaseExt}; 19use ra_db::{SourceDatabase, SourceDatabaseExt};
20use ra_prof::profile; 20use ra_prof::profile;
21use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; 21use ra_syntax::{
22 algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextUnit,
23 TokenAtOffset,
24};
22 25
23use crate::{ 26use crate::{
24 db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, 27 db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo,
@@ -35,7 +38,20 @@ pub use self::search_scope::SearchScope;
35#[derive(Debug, Clone)] 38#[derive(Debug, Clone)]
36pub struct ReferenceSearchResult { 39pub struct ReferenceSearchResult {
37 declaration: NavigationTarget, 40 declaration: NavigationTarget,
38 references: Vec<FileRange>, 41 declaration_kind: ReferenceKind,
42 references: Vec<Reference>,
43}
44
45#[derive(Debug, Clone)]
46pub struct Reference {
47 pub file_range: FileRange,
48 pub kind: ReferenceKind,
49}
50
51#[derive(Debug, Clone, PartialEq)]
52pub enum ReferenceKind {
53 StructLiteral,
54 Other,
39} 55}
40 56
41impl ReferenceSearchResult { 57impl ReferenceSearchResult {
@@ -43,7 +59,7 @@ impl ReferenceSearchResult {
43 &self.declaration 59 &self.declaration
44 } 60 }
45 61
46 pub fn references(&self) -> &[FileRange] { 62 pub fn references(&self) -> &[Reference] {
47 &self.references 63 &self.references
48 } 64 }
49 65
@@ -58,12 +74,18 @@ impl ReferenceSearchResult {
58// allow turning ReferenceSearchResult into an iterator 74// allow turning ReferenceSearchResult into an iterator
59// over FileRanges 75// over FileRanges
60impl IntoIterator for ReferenceSearchResult { 76impl IntoIterator for ReferenceSearchResult {
61 type Item = FileRange; 77 type Item = Reference;
62 type IntoIter = std::vec::IntoIter<FileRange>; 78 type IntoIter = std::vec::IntoIter<Reference>;
63 79
64 fn into_iter(mut self) -> Self::IntoIter { 80 fn into_iter(mut self) -> Self::IntoIter {
65 let mut v = Vec::with_capacity(self.len()); 81 let mut v = Vec::with_capacity(self.len());
66 v.push(FileRange { file_id: self.declaration.file_id(), range: self.declaration.range() }); 82 v.push(Reference {
83 file_range: FileRange {
84 file_id: self.declaration.file_id(),
85 range: self.declaration.range(),
86 },
87 kind: self.declaration_kind,
88 });
67 v.append(&mut self.references); 89 v.append(&mut self.references);
68 v.into_iter() 90 v.into_iter()
69 } 91 }
@@ -71,11 +93,24 @@ impl IntoIterator for ReferenceSearchResult {
71 93
72pub(crate) fn find_all_refs( 94pub(crate) fn find_all_refs(
73 db: &RootDatabase, 95 db: &RootDatabase,
74 position: FilePosition, 96 mut position: FilePosition,
75 search_scope: Option<SearchScope>, 97 search_scope: Option<SearchScope>,
76) -> Option<RangeInfo<ReferenceSearchResult>> { 98) -> Option<RangeInfo<ReferenceSearchResult>> {
77 let parse = db.parse(position.file_id); 99 let parse = db.parse(position.file_id);
78 let syntax = parse.tree().syntax().clone(); 100 let syntax = parse.tree().syntax().clone();
101
102 let token = syntax.token_at_offset(position.offset);
103 let mut search_kind = ReferenceKind::Other;
104
105 if let TokenAtOffset::Between(ref left, ref right) = token {
106 if (right.kind() == SyntaxKind::L_CURLY || right.kind() == SyntaxKind::L_PAREN)
107 && left.kind() != SyntaxKind::IDENT
108 {
109 position = FilePosition { offset: left.text_range().start(), ..position };
110 search_kind = ReferenceKind::StructLiteral;
111 }
112 }
113
79 let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; 114 let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?;
80 115
81 let declaration = match def.kind { 116 let declaration = match def.kind {
@@ -96,9 +131,15 @@ pub(crate) fn find_all_refs(
96 } 131 }
97 }; 132 };
98 133
99 let references = process_definition(db, def, name, search_scope); 134 let references = process_definition(db, def, name, search_scope)
135 .into_iter()
136 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
137 .collect();
100 138
101 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 139 Some(RangeInfo::new(
140 range,
141 ReferenceSearchResult { declaration, references, declaration_kind: ReferenceKind::Other },
142 ))
102} 143}
103 144
104fn find_name<'a>( 145fn find_name<'a>(
@@ -122,7 +163,7 @@ fn process_definition(
122 def: NameDefinition, 163 def: NameDefinition,
123 name: String, 164 name: String,
124 scope: SearchScope, 165 scope: SearchScope,
125) -> Vec<FileRange> { 166) -> Vec<Reference> {
126 let _p = profile("process_definition"); 167 let _p = profile("process_definition");
127 168
128 let pat = name.as_str(); 169 let pat = name.as_str();
@@ -146,7 +187,21 @@ fn process_definition(
146 } 187 }
147 if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) { 188 if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) {
148 if d == def { 189 if d == def {
149 refs.push(FileRange { file_id, range }); 190 let kind = if name_ref
191 .syntax()
192 .ancestors()
193 .find_map(ast::RecordLit::cast)
194 .and_then(|l| l.path())
195 .and_then(|p| p.segment())
196 .and_then(|p| p.name_ref())
197 .map(|n| n == name_ref)
198 .unwrap_or(false)
199 {
200 ReferenceKind::StructLiteral
201 } else {
202 ReferenceKind::Other
203 };
204 refs.push(Reference { file_range: FileRange { file_id, range }, kind });
150 } 205 }
151 } 206 }
152 } 207 }
@@ -163,6 +218,24 @@ mod tests {
163 }; 218 };
164 219
165 #[test] 220 #[test]
221 fn test_struct_literal() {
222 let code = r#"
223 struct Foo <|>{
224 a: i32,
225 }
226 impl Foo {
227 fn f() -> i32 { 42 }
228 }
229 fn main() {
230 let f: Foo;
231 f = Foo {a: Foo::f()};
232 }"#;
233
234 let refs = get_all_refs(code);
235 assert_eq!(refs.len(), 2);
236 }
237
238 #[test]
166 fn test_find_all_refs_for_local() { 239 fn test_find_all_refs_for_local() {
167 let code = r#" 240 let code = r#"
168 fn main() { 241 fn main() {
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index b804d5f6d..e02985dcd 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -110,7 +110,13 @@ fn rename_reference(
110 110
111 let edit = refs 111 let edit = refs
112 .into_iter() 112 .into_iter()
113 .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name)) 113 .map(|reference| {
114 source_edit_from_file_id_range(
115 reference.file_range.file_id,
116 reference.file_range.range,
117 new_name,
118 )
119 })
114 .collect::<Vec<_>>(); 120 .collect::<Vec<_>>();
115 121
116 if edit.is_empty() { 122 if edit.is_empty() {