diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 65 | ||||
-rw-r--r-- | crates/ide/src/goto_implementation.rs | 70 | ||||
-rw-r--r-- | crates/ide/src/goto_type_definition.rs | 32 |
3 files changed, 146 insertions, 21 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 27d347dbd..dcac7c76d 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -299,10 +299,10 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | |||
299 | 299 | ||
300 | #[cfg(test)] | 300 | #[cfg(test)] |
301 | mod tests { | 301 | mod tests { |
302 | use expect_test::{expect, Expect}; | 302 | use expect_test::Expect; |
303 | use ide_assists::AssistResolveStrategy; | 303 | use ide_assists::AssistResolveStrategy; |
304 | use stdx::trim_indent; | 304 | use stdx::trim_indent; |
305 | use test_utils::assert_eq_text; | 305 | use test_utils::{assert_eq_text, extract_annotations}; |
306 | 306 | ||
307 | use crate::{fixture, DiagnosticsConfig}; | 307 | use crate::{fixture, DiagnosticsConfig}; |
308 | 308 | ||
@@ -396,26 +396,51 @@ mod tests { | |||
396 | expect.assert_debug_eq(&diagnostics) | 396 | expect.assert_debug_eq(&diagnostics) |
397 | } | 397 | } |
398 | 398 | ||
399 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
400 | let (analysis, file_id) = fixture::file(ra_fixture); | ||
401 | let diagnostics = analysis | ||
402 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) | ||
403 | .unwrap(); | ||
404 | |||
405 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | ||
406 | let actual = diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); | ||
407 | assert_eq!(expected, actual); | ||
408 | } | ||
409 | |||
399 | #[test] | 410 | #[test] |
400 | fn test_unresolved_macro_range() { | 411 | fn test_unresolved_macro_range() { |
401 | check_expect( | 412 | check_diagnostics( |
402 | r#"foo::bar!(92);"#, | 413 | r#" |
403 | expect![[r#" | 414 | foo::bar!(92); |
404 | [ | 415 | //^^^ unresolved macro `foo::bar!` |
405 | Diagnostic { | 416 | "#, |
406 | message: "unresolved macro `foo::bar!`", | 417 | ); |
407 | range: 5..8, | 418 | } |
408 | severity: Error, | 419 | |
409 | fixes: None, | 420 | #[test] |
410 | unused: false, | 421 | fn unresolved_import_in_use_tree() { |
411 | code: Some( | 422 | // Only the relevant part of a nested `use` item should be highlighted. |
412 | DiagnosticCode( | 423 | check_diagnostics( |
413 | "unresolved-macro-call", | 424 | r#" |
414 | ), | 425 | use does_exist::{Exists, DoesntExist}; |
415 | ), | 426 | //^^^^^^^^^^^ unresolved import |
416 | }, | 427 | |
417 | ] | 428 | use {does_not_exist::*, does_exist}; |
418 | "#]], | 429 | //^^^^^^^^^^^^^^^^^ unresolved import |
430 | |||
431 | use does_not_exist::{ | ||
432 | a, | ||
433 | //^ unresolved import | ||
434 | b, | ||
435 | //^ unresolved import | ||
436 | c, | ||
437 | //^ unresolved import | ||
438 | }; | ||
439 | |||
440 | mod does_exist { | ||
441 | pub struct Exists; | ||
442 | } | ||
443 | "#, | ||
419 | ); | 444 | ); |
420 | } | 445 | } |
421 | 446 | ||
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 05130a237..43356a94e 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::{Impl, Semantics}; | 1 | use hir::{AsAssocItem, Impl, Semantics}; |
2 | use ide_db::{ | 2 | use ide_db::{ |
3 | defs::{Definition, NameClass, NameRefClass}, | 3 | defs::{Definition, NameClass, NameRefClass}, |
4 | RootDatabase, | 4 | RootDatabase, |
@@ -36,6 +36,7 @@ pub(crate) fn goto_implementation( | |||
36 | } | 36 | } |
37 | ast::NameLike::Lifetime(_) => None, | 37 | ast::NameLike::Lifetime(_) => None, |
38 | }?; | 38 | }?; |
39 | |||
39 | let def = match def { | 40 | let def = match def { |
40 | Definition::ModuleDef(def) => def, | 41 | Definition::ModuleDef(def) => def, |
41 | _ => return None, | 42 | _ => return None, |
@@ -48,6 +49,18 @@ pub(crate) fn goto_implementation( | |||
48 | let module = sema.to_module_def(position.file_id)?; | 49 | let module = sema.to_module_def(position.file_id)?; |
49 | impls_for_ty(&sema, builtin.ty(sema.db, module)) | 50 | impls_for_ty(&sema, builtin.ty(sema.db, module)) |
50 | } | 51 | } |
52 | hir::ModuleDef::Function(f) => { | ||
53 | let assoc = f.as_assoc_item(sema.db)?; | ||
54 | let name = assoc.name(sema.db)?; | ||
55 | let trait_ = assoc.containing_trait(sema.db)?; | ||
56 | impls_for_trait_item(&sema, trait_, name) | ||
57 | } | ||
58 | hir::ModuleDef::Const(c) => { | ||
59 | let assoc = c.as_assoc_item(sema.db)?; | ||
60 | let name = assoc.name(sema.db)?; | ||
61 | let trait_ = assoc.containing_trait(sema.db)?; | ||
62 | impls_for_trait_item(&sema, trait_, name) | ||
63 | } | ||
51 | _ => return None, | 64 | _ => return None, |
52 | }; | 65 | }; |
53 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) | 66 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) |
@@ -64,6 +77,23 @@ fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<Na | |||
64 | .collect() | 77 | .collect() |
65 | } | 78 | } |
66 | 79 | ||
80 | fn impls_for_trait_item( | ||
81 | sema: &Semantics<RootDatabase>, | ||
82 | trait_: hir::Trait, | ||
83 | fun_name: hir::Name, | ||
84 | ) -> Vec<NavigationTarget> { | ||
85 | Impl::all_for_trait(sema.db, trait_) | ||
86 | .into_iter() | ||
87 | .filter_map(|imp| { | ||
88 | let item = imp.items(sema.db).iter().find_map(|itm| { | ||
89 | let itm_name = itm.name(sema.db)?; | ||
90 | (itm_name == fun_name).then(|| itm.clone()) | ||
91 | })?; | ||
92 | item.try_to_nav(sema.db) | ||
93 | }) | ||
94 | .collect() | ||
95 | } | ||
96 | |||
67 | #[cfg(test)] | 97 | #[cfg(test)] |
68 | mod tests { | 98 | mod tests { |
69 | use ide_db::base_db::FileRange; | 99 | use ide_db::base_db::FileRange; |
@@ -262,4 +292,42 @@ impl bool {} | |||
262 | "#, | 292 | "#, |
263 | ); | 293 | ); |
264 | } | 294 | } |
295 | |||
296 | #[test] | ||
297 | fn goto_implementation_trait_functions() { | ||
298 | check( | ||
299 | r#" | ||
300 | trait Tr { | ||
301 | fn f$0(); | ||
302 | } | ||
303 | |||
304 | struct S; | ||
305 | |||
306 | impl Tr for S { | ||
307 | fn f() { | ||
308 | //^ | ||
309 | println!("Hello, world!"); | ||
310 | } | ||
311 | } | ||
312 | "#, | ||
313 | ); | ||
314 | } | ||
315 | |||
316 | #[test] | ||
317 | fn goto_implementation_trait_assoc_const() { | ||
318 | check( | ||
319 | r#" | ||
320 | trait Tr { | ||
321 | const C$0: usize; | ||
322 | } | ||
323 | |||
324 | struct S; | ||
325 | |||
326 | impl Tr for S { | ||
327 | const C: usize = 4; | ||
328 | //^ | ||
329 | } | ||
330 | "#, | ||
331 | ); | ||
332 | } | ||
265 | } | 333 | } |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index f3284bb96..004d9cb68 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use ide_db::base_db::Upcast; | ||
1 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 3 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 4 | ||
@@ -31,6 +32,7 @@ pub(crate) fn goto_type_definition( | |||
31 | ast::Pat(it) => sema.type_of_pat(&it)?, | 32 | ast::Pat(it) => sema.type_of_pat(&it)?, |
32 | ast::SelfParam(it) => sema.type_of_self(&it)?, | 33 | ast::SelfParam(it) => sema.type_of_self(&it)?, |
33 | ast::Type(it) => sema.resolve_type(&it)?, | 34 | ast::Type(it) => sema.resolve_type(&it)?, |
35 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, | ||
34 | _ => return None, | 36 | _ => return None, |
35 | } | 37 | } |
36 | }; | 38 | }; |
@@ -161,4 +163,34 @@ impl Foo$0 {} | |||
161 | "#, | 163 | "#, |
162 | ) | 164 | ) |
163 | } | 165 | } |
166 | |||
167 | #[test] | ||
168 | fn goto_def_for_struct_field() { | ||
169 | check( | ||
170 | r#" | ||
171 | struct Bar; | ||
172 | //^^^ | ||
173 | |||
174 | struct Foo { | ||
175 | bar$0: Bar, | ||
176 | } | ||
177 | "#, | ||
178 | ); | ||
179 | } | ||
180 | |||
181 | #[test] | ||
182 | fn goto_def_for_enum_struct_field() { | ||
183 | check( | ||
184 | r#" | ||
185 | struct Bar; | ||
186 | //^^^ | ||
187 | |||
188 | enum Foo { | ||
189 | Bar { | ||
190 | bar$0: Bar | ||
191 | }, | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
164 | } | 196 | } |