diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-12-17 11:00:39 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-12-17 11:00:39 +0000 |
commit | d641bccb0ffec543fa444ba523e8d4b63078fa53 (patch) | |
tree | 6695e5ebfeb9563bf5358a0cb89abe8456ac9172 /crates/ide_db | |
parent | d21f5f7d6e13b93d64235f13ac18e447af8d59e4 (diff) | |
parent | 55faa2daa3fc8bd213038a012b1c5e9ad5fd3736 (diff) |
Merge #6907
6907: Lifetime reference search r=matklad a=Veykril
PR #6787 but rewritten to make use of the HIR now. This only applies to Lifetimes, not labels. Also Higher-Ranked Trait Bounds aren't supported yet, but I feel like this PR is big enough as is which is why I left them out after noticing I forgot about them.
Supporting renaming required slight changes in the renaming module as lifetime names aren't allowed for anything but lifetimes(and labels) and vice versa for normal names.
Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates/ide_db')
-rw-r--r-- | crates/ide_db/src/defs.rs | 59 | ||||
-rw-r--r-- | crates/ide_db/src/search.rs | 63 | ||||
-rw-r--r-- | crates/ide_db/src/symbol_index.rs | 3 |
3 files changed, 107 insertions, 18 deletions
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index d4a774261..f2d1e4c39 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -6,12 +6,12 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | db::HirDatabase, Crate, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, | 9 | db::HirDatabase, Crate, Field, HasVisibility, ImplDef, LifetimeParam, Local, MacroDef, Module, |
10 | Name, PathResolution, Semantics, TypeParam, Visibility, | 10 | ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, |
11 | }; | 11 | }; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode}, | 13 | ast::{self, AstNode}, |
14 | match_ast, SyntaxNode, | 14 | match_ast, SyntaxKind, SyntaxNode, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use crate::RootDatabase; | 17 | use crate::RootDatabase; |
@@ -25,6 +25,8 @@ pub enum Definition { | |||
25 | SelfType(ImplDef), | 25 | SelfType(ImplDef), |
26 | Local(Local), | 26 | Local(Local), |
27 | TypeParam(TypeParam), | 27 | TypeParam(TypeParam), |
28 | LifetimeParam(LifetimeParam), | ||
29 | // FIXME: Label | ||
28 | } | 30 | } |
29 | 31 | ||
30 | impl Definition { | 32 | impl Definition { |
@@ -36,6 +38,7 @@ impl Definition { | |||
36 | Definition::SelfType(it) => Some(it.module(db)), | 38 | Definition::SelfType(it) => Some(it.module(db)), |
37 | Definition::Local(it) => Some(it.module(db)), | 39 | Definition::Local(it) => Some(it.module(db)), |
38 | Definition::TypeParam(it) => Some(it.module(db)), | 40 | Definition::TypeParam(it) => Some(it.module(db)), |
41 | Definition::LifetimeParam(it) => Some(it.module(db)), | ||
39 | } | 42 | } |
40 | } | 43 | } |
41 | 44 | ||
@@ -47,6 +50,7 @@ impl Definition { | |||
47 | Definition::SelfType(_) => None, | 50 | Definition::SelfType(_) => None, |
48 | Definition::Local(_) => None, | 51 | Definition::Local(_) => None, |
49 | Definition::TypeParam(_) => None, | 52 | Definition::TypeParam(_) => None, |
53 | Definition::LifetimeParam(_) => None, | ||
50 | } | 54 | } |
51 | } | 55 | } |
52 | 56 | ||
@@ -72,6 +76,7 @@ impl Definition { | |||
72 | Definition::SelfType(_) => return None, | 76 | Definition::SelfType(_) => return None, |
73 | Definition::Local(it) => it.name(db)?, | 77 | Definition::Local(it) => it.name(db)?, |
74 | Definition::TypeParam(it) => it.name(db), | 78 | Definition::TypeParam(it) => it.name(db), |
79 | Definition::LifetimeParam(it) => it.name(db), | ||
75 | }; | 80 | }; |
76 | Some(name) | 81 | Some(name) |
77 | } | 82 | } |
@@ -229,6 +234,25 @@ impl NameClass { | |||
229 | } | 234 | } |
230 | } | 235 | } |
231 | } | 236 | } |
237 | |||
238 | pub fn classify_lifetime( | ||
239 | sema: &Semantics<RootDatabase>, | ||
240 | lifetime: &ast::Lifetime, | ||
241 | ) -> Option<NameClass> { | ||
242 | let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string()); | ||
243 | let parent = lifetime.syntax().parent()?; | ||
244 | |||
245 | match_ast! { | ||
246 | match parent { | ||
247 | ast::LifetimeParam(it) => { | ||
248 | let def = sema.to_def(&it)?; | ||
249 | Some(NameClass::Definition(Definition::LifetimeParam(def))) | ||
250 | }, | ||
251 | ast::Label(_it) => None, | ||
252 | _ => None, | ||
253 | } | ||
254 | } | ||
255 | } | ||
232 | } | 256 | } |
233 | 257 | ||
234 | #[derive(Debug)] | 258 | #[derive(Debug)] |
@@ -338,6 +362,35 @@ impl NameRefClass { | |||
338 | let resolved = sema.resolve_extern_crate(&extern_crate)?; | 362 | let resolved = sema.resolve_extern_crate(&extern_crate)?; |
339 | Some(NameRefClass::ExternCrate(resolved)) | 363 | Some(NameRefClass::ExternCrate(resolved)) |
340 | } | 364 | } |
365 | |||
366 | pub fn classify_lifetime( | ||
367 | sema: &Semantics<RootDatabase>, | ||
368 | lifetime: &ast::Lifetime, | ||
369 | ) -> Option<NameRefClass> { | ||
370 | let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string()); | ||
371 | let parent = lifetime.syntax().parent()?; | ||
372 | match parent.kind() { | ||
373 | SyntaxKind::LIFETIME_ARG | ||
374 | | SyntaxKind::SELF_PARAM | ||
375 | | SyntaxKind::TYPE_BOUND | ||
376 | | SyntaxKind::WHERE_PRED | ||
377 | | SyntaxKind::REF_TYPE => sema | ||
378 | .resolve_lifetime_param(lifetime) | ||
379 | .map(Definition::LifetimeParam) | ||
380 | .map(NameRefClass::Definition), | ||
381 | // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check | ||
382 | // if our lifetime is in a LifetimeParam without being the constrained lifetime | ||
383 | _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref() | ||
384 | != Some(lifetime) => | ||
385 | { | ||
386 | sema.resolve_lifetime_param(lifetime) | ||
387 | .map(Definition::LifetimeParam) | ||
388 | .map(NameRefClass::Definition) | ||
389 | } | ||
390 | SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => None, | ||
391 | _ => None, | ||
392 | } | ||
393 | } | ||
341 | } | 394 | } |
342 | 395 | ||
343 | impl From<PathResolution> for Definition { | 396 | impl From<PathResolution> for Definition { |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 3936c7390..5b3997bcf 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -33,6 +33,7 @@ pub enum ReferenceKind { | |||
33 | RecordFieldExprOrPat, | 33 | RecordFieldExprOrPat, |
34 | SelfKw, | 34 | SelfKw, |
35 | EnumLiteral, | 35 | EnumLiteral, |
36 | Lifetime, | ||
36 | Other, | 37 | Other, |
37 | } | 38 | } |
38 | 39 | ||
@@ -129,6 +130,25 @@ impl Definition { | |||
129 | return SearchScope::new(res); | 130 | return SearchScope::new(res); |
130 | } | 131 | } |
131 | 132 | ||
133 | if let Definition::LifetimeParam(param) = self { | ||
134 | let range = match param.parent(db) { | ||
135 | hir::GenericDef::Function(it) => it.source(db).value.syntax().text_range(), | ||
136 | hir::GenericDef::Adt(it) => match it { | ||
137 | hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(), | ||
138 | hir::Adt::Union(it) => it.source(db).value.syntax().text_range(), | ||
139 | hir::Adt::Enum(it) => it.source(db).value.syntax().text_range(), | ||
140 | }, | ||
141 | hir::GenericDef::Trait(it) => it.source(db).value.syntax().text_range(), | ||
142 | hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(), | ||
143 | hir::GenericDef::ImplDef(it) => it.source(db).value.syntax().text_range(), | ||
144 | hir::GenericDef::EnumVariant(it) => it.source(db).value.syntax().text_range(), | ||
145 | hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(), | ||
146 | }; | ||
147 | let mut res = FxHashMap::default(); | ||
148 | res.insert(file_id, Some(range)); | ||
149 | return SearchScope::new(res); | ||
150 | } | ||
151 | |||
132 | let vis = self.visibility(db); | 152 | let vis = self.visibility(db); |
133 | 153 | ||
134 | if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) { | 154 | if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) { |
@@ -255,25 +275,42 @@ impl<'a> FindUsages<'a> { | |||
255 | continue; | 275 | continue; |
256 | } | 276 | } |
257 | 277 | ||
258 | match sema.find_node_at_offset_with_descend(&tree, offset) { | 278 | if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) { |
259 | Some(name_ref) => { | 279 | if self.found_name_ref(&name_ref, sink) { |
260 | if self.found_name_ref(&name_ref, sink) { | 280 | return; |
261 | return; | 281 | } |
262 | } | 282 | } else if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) { |
283 | if self.found_name(&name, sink) { | ||
284 | return; | ||
285 | } | ||
286 | } else if let Some(lifetime) = sema.find_node_at_offset_with_descend(&tree, offset) | ||
287 | { | ||
288 | if self.found_lifetime(&lifetime, sink) { | ||
289 | return; | ||
263 | } | 290 | } |
264 | None => match sema.find_node_at_offset_with_descend(&tree, offset) { | ||
265 | Some(name) => { | ||
266 | if self.found_name(&name, sink) { | ||
267 | return; | ||
268 | } | ||
269 | } | ||
270 | None => {} | ||
271 | }, | ||
272 | } | 291 | } |
273 | } | 292 | } |
274 | } | 293 | } |
275 | } | 294 | } |
276 | 295 | ||
296 | fn found_lifetime( | ||
297 | &self, | ||
298 | lifetime: &ast::Lifetime, | ||
299 | sink: &mut dyn FnMut(Reference) -> bool, | ||
300 | ) -> bool { | ||
301 | match NameRefClass::classify_lifetime(self.sema, lifetime) { | ||
302 | Some(NameRefClass::Definition(def)) if &def == self.def => { | ||
303 | let reference = Reference { | ||
304 | file_range: self.sema.original_range(lifetime.syntax()), | ||
305 | kind: ReferenceKind::Lifetime, | ||
306 | access: None, | ||
307 | }; | ||
308 | sink(reference) | ||
309 | } | ||
310 | _ => false, // not a usage | ||
311 | } | ||
312 | } | ||
313 | |||
277 | fn found_name_ref( | 314 | fn found_name_ref( |
278 | &self, | 315 | &self, |
279 | name_ref: &ast::NameRef, | 316 | name_ref: &ast::NameRef, |
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 121063aea..ca455fa03 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs | |||
@@ -209,8 +209,7 @@ pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<Fil | |||
209 | query.search(&buf) | 209 | query.search(&buf) |
210 | } | 210 | } |
211 | 211 | ||
212 | pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> { | 212 | pub fn index_resolve(db: &RootDatabase, name: &SmolStr) -> Vec<FileSymbol> { |
213 | let name = name_ref.text(); | ||
214 | let mut query = Query::new(name.to_string()); | 213 | let mut query = Query::new(name.to_string()); |
215 | query.exact(); | 214 | query.exact(); |
216 | query.limit(4); | 215 | query.limit(4); |