aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-11-28 21:55:34 +0000
committerLukas Wirth <[email protected]>2020-11-29 19:54:17 +0000
commitde4ada22d484950a6f416f25c85566ea9d1830a9 (patch)
tree1cdc2df44c2cece831bff7f0fd3a500ce5880e41 /crates/ide
parenta6f26ded0037a3efb5625ac3482a2f4ec9eb01a3 (diff)
Support self in reference search
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/references.rs103
1 files changed, 102 insertions, 1 deletions
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 5693dd400..7395b81bd 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -21,7 +21,7 @@ use ide_db::{
21use syntax::{ 21use syntax::{
22 algo::find_node_at_offset, 22 algo::find_node_at_offset,
23 ast::{self, NameOwner}, 23 ast::{self, NameOwner},
24 AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset, 24 match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset,
25}; 25};
26 26
27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; 27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
@@ -89,6 +89,10 @@ pub(crate) fn find_all_refs(
89 let _p = profile::span("find_all_refs"); 89 let _p = profile::span("find_all_refs");
90 let syntax = sema.parse(position.file_id).syntax().clone(); 90 let syntax = sema.parse(position.file_id).syntax().clone();
91 91
92 if let Some(res) = try_find_self_references(&syntax, position) {
93 return Some(res);
94 }
95
92 let (opt_name, search_kind) = if let Some(name) = 96 let (opt_name, search_kind) = if let Some(name) =
93 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position) 97 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
94 { 98 {
@@ -194,6 +198,77 @@ fn get_struct_def_name_for_struct_literal_search(
194 None 198 None
195} 199}
196 200
201fn try_find_self_references(
202 syntax: &SyntaxNode,
203 position: FilePosition,
204) -> Option<RangeInfo<ReferenceSearchResult>> {
205 let self_token =
206 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)?;
207 let parent = self_token.parent();
208 match_ast! {
209 match parent {
210 ast::SelfParam(it) => (),
211 ast::PathSegment(segment) => {
212 segment.self_token()?;
213 let path = segment.parent_path();
214 if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) {
215 return None;
216 }
217 },
218 _ => return None,
219 }
220 };
221 let function = parent.ancestors().find_map(ast::Fn::cast)?;
222 let self_param = function.param_list()?.self_param()?;
223 let param_self_token = self_param.self_token()?;
224
225 let declaration = Declaration {
226 nav: NavigationTarget {
227 file_id: position.file_id,
228 full_range: self_param.syntax().text_range(),
229 focus_range: Some(param_self_token.text_range()),
230 name: param_self_token.text().clone(),
231 kind: param_self_token.kind(),
232 container_name: None,
233 description: None,
234 docs: None,
235 },
236 kind: ReferenceKind::SelfKw,
237 access: Some(if self_param.mut_token().is_some() {
238 ReferenceAccess::Write
239 } else {
240 ReferenceAccess::Read
241 }),
242 };
243 let references = function
244 .body()
245 .map(|body| {
246 body.syntax()
247 .descendants()
248 .filter_map(ast::PathExpr::cast)
249 .filter_map(|expr| {
250 let path = expr.path()?;
251 if path.qualifier().is_none() {
252 path.segment()?.self_token()
253 } else {
254 None
255 }
256 })
257 .map(|token| Reference {
258 file_range: FileRange { file_id: position.file_id, range: token.text_range() },
259 kind: ReferenceKind::SelfKw,
260 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
261 })
262 .collect()
263 })
264 .unwrap_or_default();
265
266 Some(RangeInfo::new(
267 param_self_token.text_range(),
268 ReferenceSearchResult { declaration, references },
269 ))
270}
271
197#[cfg(test)] 272#[cfg(test)]
198mod tests { 273mod tests {
199 use expect_test::{expect, Expect}; 274 use expect_test::{expect, Expect};
@@ -762,6 +837,32 @@ fn f() -> m::En {
762 ); 837 );
763 } 838 }
764 839
840 #[test]
841 fn test_find_self_refs() {
842 check(
843 r#"
844struct Foo { bar: i32 }
845
846impl Foo {
847 fn foo(self) {
848 let x = self<|>.bar;
849 if true {
850 let _ = match () {
851 () => self,
852 };
853 }
854 }
855}
856"#,
857 expect![[r#"
858 self SELF_KW FileId(0) 47..51 47..51 SelfKw Read
859
860 FileId(0) 71..75 SelfKw Read
861 FileId(0) 152..156 SelfKw Read
862 "#]],
863 );
864 }
865
765 fn check(ra_fixture: &str, expect: Expect) { 866 fn check(ra_fixture: &str, expect: Expect) {
766 check_with_scope(ra_fixture, None, expect) 867 check_with_scope(ra_fixture, None, expect)
767 } 868 }