|
4 | 4 | //! get a super-set of matches. Then, we we confirm each match using precise
|
5 | 5 | //! name resolution.
|
6 | 6 |
|
7 |
| -use std::{convert::TryInto, mem}; |
| 7 | +use std::{convert::TryInto, iter, mem}; |
8 | 8 |
|
9 | 9 | use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
|
10 |
| -use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; |
| 10 | +use either::Either; |
| 11 | +use hir::{ |
| 12 | + DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics, Visibility, |
| 13 | +}; |
11 | 14 | use once_cell::unsync::Lazy;
|
12 | 15 | use rustc_hash::FxHashMap;
|
13 | 16 | use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
|
@@ -295,17 +298,23 @@ impl Definition {
|
295 | 298 | }
|
296 | 299 |
|
297 | 300 | pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
|
298 |
| - FindUsages { def: self, sema, scope: None } |
| 301 | + FindUsages { def: self, sema, scope: None, include_self_kw_refs: false } |
299 | 302 | }
|
300 | 303 | }
|
301 | 304 |
|
302 | 305 | pub struct FindUsages<'a> {
|
303 | 306 | def: &'a Definition,
|
304 | 307 | sema: &'a Semantics<'a, RootDatabase>,
|
305 | 308 | scope: Option<SearchScope>,
|
| 309 | + include_self_kw_refs: bool, |
306 | 310 | }
|
307 | 311 |
|
308 | 312 | impl<'a> FindUsages<'a> {
|
| 313 | + pub fn include_self_kw_refs(mut self, include: bool) -> FindUsages<'a> { |
| 314 | + self.include_self_kw_refs = include; |
| 315 | + self |
| 316 | + } |
| 317 | + |
309 | 318 | pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
|
310 | 319 | self.set_scope(Some(scope))
|
311 | 320 | }
|
@@ -352,14 +361,22 @@ impl<'a> FindUsages<'a> {
|
352 | 361 | };
|
353 | 362 |
|
354 | 363 | let pat = name.as_str();
|
| 364 | + let search_for_self = self.include_self_kw_refs; |
| 365 | + |
355 | 366 | for (file_id, search_range) in search_scope {
|
356 | 367 | let text = sema.db.file_text(file_id);
|
357 | 368 | let search_range =
|
358 | 369 | search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
|
359 | 370 |
|
360 | 371 | let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
|
361 | 372 |
|
362 |
| - for (idx, _) in text.match_indices(pat) { |
| 373 | + let matches = text.match_indices(pat).chain(if search_for_self { |
| 374 | + Either::Left(text.match_indices("Self")) |
| 375 | + } else { |
| 376 | + Either::Right(iter::empty()) |
| 377 | + }); |
| 378 | + |
| 379 | + for (idx, _) in matches { |
363 | 380 | let offset: TextSize = idx.try_into().unwrap();
|
364 | 381 | if !search_range.contains_inclusive(offset) {
|
365 | 382 | continue;
|
@@ -413,6 +430,24 @@ impl<'a> FindUsages<'a> {
|
413 | 430 | sink: &mut dyn FnMut(FileId, FileReference) -> bool,
|
414 | 431 | ) -> bool {
|
415 | 432 | match NameRefClass::classify(self.sema, &name_ref) {
|
| 433 | + Some(NameRefClass::Definition(Definition::SelfType(impl_))) => { |
| 434 | + let ty = impl_.self_ty(self.sema.db); |
| 435 | + |
| 436 | + if let Some(adt) = ty.as_adt() { |
| 437 | + if &Definition::ModuleDef(ModuleDef::Adt(adt)) == self.def { |
| 438 | + let FileRange { file_id, range } = |
| 439 | + self.sema.original_range(name_ref.syntax()); |
| 440 | + let reference = FileReference { |
| 441 | + range, |
| 442 | + name: ast::NameLike::NameRef(name_ref.clone()), |
| 443 | + access: None, |
| 444 | + }; |
| 445 | + return sink(file_id, reference); |
| 446 | + } |
| 447 | + } |
| 448 | + |
| 449 | + false |
| 450 | + } |
416 | 451 | Some(NameRefClass::Definition(def)) if &def == self.def => {
|
417 | 452 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
|
418 | 453 | let reference = FileReference {
|
|
0 commit comments