Skip to content

Commit ac30710

Browse files
bors[bot]Veykril
andauthored
Merge #6665
6665: Support self in reference search r=matklad a=Veykril The approach here is simply checking the descendants of the function body for `PathExpr` then checking whether it only contains a single `self` `PathSegment`, this is to prevent us from picking up `self` tokens from local `UseTree`s. Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2 parents 25ebcca + de4ada2 commit ac30710

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

crates/ide/src/references.rs

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use ide_db::{
2121
use syntax::{
2222
algo::find_node_at_offset,
2323
ast::{self, NameOwner},
24-
AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset,
24+
match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset,
2525
};
2626

2727
use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
@@ -89,6 +89,10 @@ pub(crate) fn find_all_refs(
8989
let _p = profile::span("find_all_refs");
9090
let syntax = sema.parse(position.file_id).syntax().clone();
9191

92+
if let Some(res) = try_find_self_references(&syntax, position) {
93+
return Some(res);
94+
}
95+
9296
let (opt_name, search_kind) = if let Some(name) =
9397
get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
9498
{
@@ -194,6 +198,77 @@ fn get_struct_def_name_for_struct_literal_search(
194198
None
195199
}
196200

201+
fn 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+
197272
#[cfg(test)]
198273
mod tests {
199274
use expect_test::{expect, Expect};
@@ -762,6 +837,32 @@ fn f() -> m::En {
762837
);
763838
}
764839

840+
#[test]
841+
fn test_find_self_refs() {
842+
check(
843+
r#"
844+
struct Foo { bar: i32 }
845+
846+
impl 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+
765866
fn check(ra_fixture: &str, expect: Expect) {
766867
check_with_scope(ra_fixture, None, expect)
767868
}

crates/ide_db/src/search.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub enum ReferenceKind {
3131
FieldShorthandForLocal,
3232
StructLiteral,
3333
RecordFieldExprOrPat,
34+
SelfKw,
3435
Other,
3536
}
3637

0 commit comments

Comments
 (0)