aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/hover.rs
diff options
context:
space:
mode:
authorDmitry <[email protected]>2020-08-14 19:32:05 +0100
committerDmitry <[email protected]>2020-08-14 19:32:05 +0100
commit178c3e135a2a249692f7784712492e7884ae0c00 (patch)
treeac6b769dbf7162150caa0c1624786a4dd79ff3be /crates/ide/src/hover.rs
parent06ff8e6c760ff05f10e868b5d1f9d79e42fbb49c (diff)
parentc2594daf2974dbd4ce3d9b7ec72481764abaceb5 (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'crates/ide/src/hover.rs')
-rw-r--r--crates/ide/src/hover.rs2480
1 files changed, 2480 insertions, 0 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
new file mode 100644
index 000000000..300c00edc
--- /dev/null
+++ b/crates/ide/src/hover.rs
@@ -0,0 +1,2480 @@
1use base_db::SourceDatabase;
2use hir::{
3 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay,
4 Module, ModuleDef, ModuleSource, Semantics,
5};
6use ide_db::{
7 defs::{classify_name, classify_name_ref, Definition},
8 RootDatabase,
9};
10use itertools::Itertools;
11use stdx::format_to;
12use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
13use test_utils::mark;
14
15use crate::{
16 display::{macro_label, ShortLabel, ToNav, TryToNav},
17 markup::Markup,
18 runnables::runnable,
19 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
20};
21
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct HoverConfig {
24 pub implementations: bool,
25 pub run: bool,
26 pub debug: bool,
27 pub goto_type_def: bool,
28}
29
30impl Default for HoverConfig {
31 fn default() -> Self {
32 Self { implementations: true, run: true, debug: true, goto_type_def: true }
33 }
34}
35
36impl HoverConfig {
37 pub const NO_ACTIONS: Self =
38 Self { implementations: false, run: false, debug: false, goto_type_def: false };
39
40 pub fn any(&self) -> bool {
41 self.implementations || self.runnable() || self.goto_type_def
42 }
43
44 pub fn none(&self) -> bool {
45 !self.any()
46 }
47
48 pub fn runnable(&self) -> bool {
49 self.run || self.debug
50 }
51}
52
53#[derive(Debug, Clone)]
54pub enum HoverAction {
55 Runnable(Runnable),
56 Implementaion(FilePosition),
57 GoToType(Vec<HoverGotoTypeData>),
58}
59
60#[derive(Debug, Clone, Eq, PartialEq)]
61pub struct HoverGotoTypeData {
62 pub mod_path: String,
63 pub nav: NavigationTarget,
64}
65
66/// Contains the results when hovering over an item
67#[derive(Debug, Default)]
68pub struct HoverResult {
69 pub markup: Markup,
70 pub actions: Vec<HoverAction>,
71}
72
73// Feature: Hover
74//
75// Shows additional information, like type of an expression or documentation for definition when "focusing" code.
76// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
77pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
78 let sema = Semantics::new(db);
79 let file = sema.parse(position.file_id).syntax().clone();
80 let token = pick_best(file.token_at_offset(position.offset))?;
81 let token = sema.descend_into_macros(token);
82
83 let mut res = HoverResult::default();
84
85 let node = token.parent();
86 let definition = match_ast! {
87 match node {
88 ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition(sema.db)),
89 ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition(sema.db)),
90 _ => None,
91 }
92 };
93 if let Some(definition) = definition {
94 if let Some(markup) = hover_for_definition(db, definition) {
95 res.markup = markup;
96 if let Some(action) = show_implementations_action(db, definition) {
97 res.actions.push(action);
98 }
99
100 if let Some(action) = runnable_action(&sema, definition, position.file_id) {
101 res.actions.push(action);
102 }
103
104 if let Some(action) = goto_type_action(db, definition) {
105 res.actions.push(action);
106 }
107
108 let range = sema.original_range(&node).range;
109 return Some(RangeInfo::new(range, res));
110 }
111 }
112
113 let node = token
114 .ancestors()
115 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
116
117 let ty = match_ast! {
118 match node {
119 ast::Expr(it) => sema.type_of_expr(&it)?,
120 ast::Pat(it) => sema.type_of_pat(&it)?,
121 // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve.
122 // (e.g expanding a builtin macro). So we give up here.
123 ast::MacroCall(_it) => return None,
124 _ => return None,
125 }
126 };
127
128 res.markup = Markup::fenced_block(&ty.display(db));
129 let range = sema.original_range(&node).range;
130 Some(RangeInfo::new(range, res))
131}
132
133fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
134 fn to_action(nav_target: NavigationTarget) -> HoverAction {
135 HoverAction::Implementaion(FilePosition {
136 file_id: nav_target.file_id,
137 offset: nav_target.focus_or_full_range().start(),
138 })
139 }
140
141 match def {
142 Definition::ModuleDef(it) => match it {
143 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))),
144 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))),
145 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))),
146 ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))),
147 _ => None,
148 },
149 _ => None,
150 }
151}
152
153fn runnable_action(
154 sema: &Semantics<RootDatabase>,
155 def: Definition,
156 file_id: FileId,
157) -> Option<HoverAction> {
158 match def {
159 Definition::ModuleDef(it) => match it {
160 ModuleDef::Module(it) => match it.definition_source(sema.db).value {
161 ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id)
162 .map(|it| HoverAction::Runnable(it)),
163 _ => None,
164 },
165 ModuleDef::Function(it) => {
166 let src = it.source(sema.db);
167 if src.file_id != file_id.into() {
168 mark::hit!(hover_macro_generated_struct_fn_doc_comment);
169 mark::hit!(hover_macro_generated_struct_fn_doc_attr);
170
171 return None;
172 }
173
174 runnable(&sema, src.value.syntax().clone(), file_id)
175 .map(|it| HoverAction::Runnable(it))
176 }
177 _ => None,
178 },
179 _ => None,
180 }
181}
182
183fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
184 match def {
185 Definition::Local(it) => {
186 let mut targets: Vec<ModuleDef> = Vec::new();
187 let mut push_new_def = |item: ModuleDef| {
188 if !targets.contains(&item) {
189 targets.push(item);
190 }
191 };
192
193 it.ty(db).walk(db, |t| {
194 if let Some(adt) = t.as_adt() {
195 push_new_def(adt.into());
196 } else if let Some(trait_) = t.as_dyn_trait() {
197 push_new_def(trait_.into());
198 } else if let Some(traits) = t.as_impl_traits(db) {
199 traits.into_iter().for_each(|it| push_new_def(it.into()));
200 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
201 push_new_def(trait_.into());
202 }
203 });
204
205 let targets = targets
206 .into_iter()
207 .filter_map(|it| {
208 Some(HoverGotoTypeData {
209 mod_path: render_path(
210 db,
211 it.module(db)?,
212 it.name(db).map(|name| name.to_string()),
213 ),
214 nav: it.try_to_nav(db)?,
215 })
216 })
217 .collect();
218
219 Some(HoverAction::GoToType(targets))
220 }
221 _ => None,
222 }
223}
224
225fn hover_markup(
226 docs: Option<String>,
227 desc: Option<String>,
228 mod_path: Option<String>,
229) -> Option<Markup> {
230 match desc {
231 Some(desc) => {
232 let mut buf = String::new();
233
234 if let Some(mod_path) = mod_path {
235 if !mod_path.is_empty() {
236 format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
237 }
238 }
239 format_to!(buf, "```rust\n{}\n```", desc);
240
241 if let Some(doc) = docs {
242 format_to!(buf, "\n___\n\n{}", doc);
243 }
244 Some(buf.into())
245 }
246 None => docs.map(Markup::from),
247 }
248}
249
250fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
251 match def {
252 Definition::Field(f) => Some(f.parent_def(db).name(db)),
253 Definition::Local(l) => l.parent(db).name(db),
254 Definition::ModuleDef(md) => match md {
255 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
256 AssocItemContainer::Trait(t) => Some(t.name(db)),
257 AssocItemContainer::ImplDef(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
258 },
259 ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)),
260 _ => None,
261 },
262 Definition::SelfType(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
263 _ => None,
264 }
265 .map(|name| name.to_string())
266}
267
268fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String {
269 let crate_name =
270 db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string);
271 let module_path = module
272 .path_to_root(db)
273 .into_iter()
274 .rev()
275 .flat_map(|it| it.name(db).map(|name| name.to_string()));
276 crate_name.into_iter().chain(module_path).chain(item_name).join("::")
277}
278
279fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
280 def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
281}
282
283fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
284 let mod_path = definition_mod_path(db, &def);
285 return match def {
286 Definition::Macro(it) => {
287 let src = it.source(db);
288 let docs = Documentation::from_ast(&src.value).map(Into::into);
289 hover_markup(docs, Some(macro_label(&src.value)), mod_path)
290 }
291 Definition::Field(it) => {
292 let src = it.source(db);
293 match src.value {
294 FieldSource::Named(it) => {
295 let docs = Documentation::from_ast(&it).map(Into::into);
296 hover_markup(docs, it.short_label(), mod_path)
297 }
298 _ => None,
299 }
300 }
301 Definition::ModuleDef(it) => match it {
302 ModuleDef::Module(it) => match it.definition_source(db).value {
303 ModuleSource::Module(it) => {
304 let docs = Documentation::from_ast(&it).map(Into::into);
305 hover_markup(docs, it.short_label(), mod_path)
306 }
307 ModuleSource::SourceFile(it) => {
308 let docs = Documentation::from_ast(&it).map(Into::into);
309 hover_markup(docs, it.short_label(), mod_path)
310 }
311 },
312 ModuleDef::Function(it) => from_def_source(db, it, mod_path),
313 ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
314 ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
315 ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path),
316 ModuleDef::EnumVariant(it) => from_def_source(db, it, mod_path),
317 ModuleDef::Const(it) => from_def_source(db, it, mod_path),
318 ModuleDef::Static(it) => from_def_source(db, it, mod_path),
319 ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
320 ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
321 ModuleDef::BuiltinType(it) => return Some(it.to_string().into()),
322 },
323 Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))),
324 Definition::TypeParam(_) | Definition::SelfType(_) => {
325 // FIXME: Hover for generic param
326 None
327 }
328 };
329
330 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
331 where
332 D: HasSource<Ast = A>,
333 A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner,
334 {
335 let src = def.source(db);
336 let docs = Documentation::from_ast(&src.value).map(Into::into);
337 hover_markup(docs, src.value.short_label(), mod_path)
338 }
339}
340
341fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
342 return tokens.max_by_key(priority);
343 fn priority(n: &SyntaxToken) -> usize {
344 match n.kind() {
345 IDENT | INT_NUMBER => 3,
346 T!['('] | T![')'] => 2,
347 kind if kind.is_trivia() => 0,
348 _ => 1,
349 }
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use base_db::FileLoader;
356 use expect::{expect, Expect};
357
358 use crate::mock_analysis::analysis_and_position;
359
360 use super::*;
361
362 fn check_hover_no_result(ra_fixture: &str) {
363 let (analysis, position) = analysis_and_position(ra_fixture);
364 assert!(analysis.hover(position).unwrap().is_none());
365 }
366
367 fn check(ra_fixture: &str, expect: Expect) {
368 let (analysis, position) = analysis_and_position(ra_fixture);
369 let hover = analysis.hover(position).unwrap().unwrap();
370
371 let content = analysis.db.file_text(position.file_id);
372 let hovered_element = &content[hover.range];
373
374 let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
375 expect.assert_eq(&actual)
376 }
377
378 fn check_actions(ra_fixture: &str, expect: Expect) {
379 let (analysis, position) = analysis_and_position(ra_fixture);
380 let hover = analysis.hover(position).unwrap().unwrap();
381 expect.assert_debug_eq(&hover.info.actions)
382 }
383
384 #[test]
385 fn hover_shows_type_of_an_expression() {
386 check(
387 r#"
388pub fn foo() -> u32 { 1 }
389
390fn main() {
391 let foo_test = foo()<|>;
392}
393"#,
394 expect![[r#"
395 *foo()*
396 ```rust
397 u32
398 ```
399 "#]],
400 );
401 }
402
403 #[test]
404 fn hover_shows_long_type_of_an_expression() {
405 check(
406 r#"
407struct Scan<A, B, C> { a: A, b: B, c: C }
408struct Iter<I> { inner: I }
409enum Option<T> { Some(T), None }
410
411struct OtherStruct<T> { i: T }
412
413fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, B, C>> {
414 Iter { inner: Scan { a, b, c } }
415}
416
417fn main() {
418 let num: i32 = 55;
419 let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option<u32> {
420 Option::Some(*memo + value)
421 };
422 let number = 5u32;
423 let mut iter<|> = scan(OtherStruct { i: num }, closure, number);
424}
425"#,
426 expect![[r#"
427 *iter*
428 ```rust
429 Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
430 ```
431 "#]],
432 );
433 }
434
435 #[test]
436 fn hover_shows_fn_signature() {
437 // Single file with result
438 check(
439 r#"
440pub fn foo() -> u32 { 1 }
441
442fn main() { let foo_test = fo<|>o(); }
443"#,
444 expect![[r#"
445 *foo*
446 ```rust
447 pub fn foo() -> u32
448 ```
449 "#]],
450 );
451
452 // Multiple candidates but results are ambiguous.
453 check(
454 r#"
455//- /a.rs
456pub fn foo() -> u32 { 1 }
457
458//- /b.rs
459pub fn foo() -> &str { "" }
460
461//- /c.rs
462pub fn foo(a: u32, b: u32) {}
463
464//- /main.rs
465mod a;
466mod b;
467mod c;
468
469fn main() { let foo_test = fo<|>o(); }
470 "#,
471 expect![[r#"
472 *foo*
473 ```rust
474 {unknown}
475 ```
476 "#]],
477 );
478 }
479
480 #[test]
481 fn hover_shows_fn_signature_with_type_params() {
482 check(
483 r#"
484pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
485
486fn main() { let foo_test = fo<|>o(); }
487 "#,
488 expect![[r#"
489 *foo*
490 ```rust
491 pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
492 ```
493 "#]],
494 );
495 }
496
497 #[test]
498 fn hover_shows_fn_signature_on_fn_name() {
499 check(
500 r#"
501pub fn foo<|>(a: u32, b: u32) -> u32 {}
502
503fn main() { }
504"#,
505 expect![[r#"
506 *foo*
507 ```rust
508 pub fn foo(a: u32, b: u32) -> u32
509 ```
510 "#]],
511 );
512 }
513
514 #[test]
515 fn hover_shows_fn_doc() {
516 check(
517 r#"
518/// # Example
519/// ```
520/// # use std::path::Path;
521/// #
522/// foo(Path::new("hello, world!"))
523/// ```
524pub fn foo<|>(_: &Path) {}
525
526fn main() { }
527"#,
528 expect![[r#"
529 *foo*
530 ```rust
531 pub fn foo(_: &Path)
532 ```
533 ___
534
535 # Example
536 ```
537 # use std::path::Path;
538 #
539 foo(Path::new("hello, world!"))
540 ```
541 "#]],
542 );
543 }
544
545 #[test]
546 fn hover_shows_struct_field_info() {
547 // Hovering over the field when instantiating
548 check(
549 r#"
550struct Foo { field_a: u32 }
551
552fn main() {
553 let foo = Foo { field_a<|>: 0, };
554}
555"#,
556 expect![[r#"
557 *field_a*
558 ```rust
559 Foo
560 ```
561
562 ```rust
563 field_a: u32
564 ```
565 "#]],
566 );
567
568 // Hovering over the field in the definition
569 check(
570 r#"
571struct Foo { field_a<|>: u32 }
572
573fn main() {
574 let foo = Foo { field_a: 0 };
575}
576"#,
577 expect![[r#"
578 *field_a*
579 ```rust
580 Foo
581 ```
582
583 ```rust
584 field_a: u32
585 ```
586 "#]],
587 );
588 }
589
590 #[test]
591 fn hover_const_static() {
592 check(
593 r#"const foo<|>: u32 = 123;"#,
594 expect![[r#"
595 *foo*
596 ```rust
597 const foo: u32 = 123
598 ```
599 "#]],
600 );
601 check(
602 r#"static foo<|>: u32 = 456;"#,
603 expect![[r#"
604 *foo*
605 ```rust
606 static foo: u32
607 ```
608 "#]],
609 );
610 }
611
612 #[test]
613 fn hover_default_generic_types() {
614 check(
615 r#"
616struct Test<K, T = u8> { k: K, t: T }
617
618fn main() {
619 let zz<|> = Test { t: 23u8, k: 33 };
620}"#,
621 expect![[r#"
622 *zz*
623 ```rust
624 Test<i32, u8>
625 ```
626 "#]],
627 );
628 }
629
630 #[test]
631 fn hover_some() {
632 check(
633 r#"
634enum Option<T> { Some(T) }
635use Option::Some;
636
637fn main() { So<|>me(12); }
638"#,
639 expect![[r#"
640 *Some*
641 ```rust
642 Option
643 ```
644
645 ```rust
646 Some
647 ```
648 "#]],
649 );
650
651 check(
652 r#"
653enum Option<T> { Some(T) }
654use Option::Some;
655
656fn main() { let b<|>ar = Some(12); }
657"#,
658 expect![[r#"
659 *bar*
660 ```rust
661 Option<i32>
662 ```
663 "#]],
664 );
665 }
666
667 #[test]
668 fn hover_enum_variant() {
669 check(
670 r#"
671enum Option<T> {
672 /// The None variant
673 Non<|>e
674}
675"#,
676 expect![[r#"
677 *None*
678 ```rust
679 Option
680 ```
681
682 ```rust
683 None
684 ```
685 ___
686
687 The None variant
688 "#]],
689 );
690
691 check(
692 r#"
693enum Option<T> {
694 /// The Some variant
695 Some(T)
696}
697fn main() {
698 let s = Option::Som<|>e(12);
699}
700"#,
701 expect![[r#"
702 *Some*
703 ```rust
704 Option
705 ```
706
707 ```rust
708 Some
709 ```
710 ___
711
712 The Some variant
713 "#]],
714 );
715 }
716
717 #[test]
718 fn hover_for_local_variable() {
719 check(
720 r#"fn func(foo: i32) { fo<|>o; }"#,
721 expect![[r#"
722 *foo*
723 ```rust
724 i32
725 ```
726 "#]],
727 )
728 }
729
730 #[test]
731 fn hover_for_local_variable_pat() {
732 check(
733 r#"fn func(fo<|>o: i32) {}"#,
734 expect![[r#"
735 *foo*
736 ```rust
737 i32
738 ```
739 "#]],
740 )
741 }
742
743 #[test]
744 fn hover_local_var_edge() {
745 check(
746 r#"fn func(foo: i32) { if true { <|>foo; }; }"#,
747 expect![[r#"
748 *foo*
749 ```rust
750 i32
751 ```
752 "#]],
753 )
754 }
755
756 #[test]
757 fn hover_for_param_edge() {
758 check(
759 r#"fn func(<|>foo: i32) {}"#,
760 expect![[r#"
761 *foo*
762 ```rust
763 i32
764 ```
765 "#]],
766 )
767 }
768
769 #[test]
770 fn hover_for_param_with_multiple_traits() {
771 check(
772 r#"trait Deref {
773 type Target: ?Sized;
774 }
775 trait DerefMut {
776 type Target: ?Sized;
777 }
778 fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
779 expect![[r#"
780 *_x*
781 ```rust
782 impl Deref<Target = u8> + DerefMut<Target = u8>
783 ```
784 "#]],
785 )
786 }
787
788 #[test]
789 fn test_hover_infer_associated_method_result() {
790 check(
791 r#"
792struct Thing { x: u32 }
793
794impl Thing {
795 fn new() -> Thing { Thing { x: 0 } }
796}
797
798fn main() { let foo_<|>test = Thing::new(); }
799 "#,
800 expect![[r#"
801 *foo_test*
802 ```rust
803 Thing
804 ```
805 "#]],
806 )
807 }
808
809 #[test]
810 fn test_hover_infer_associated_method_exact() {
811 check(
812 r#"
813mod wrapper {
814 struct Thing { x: u32 }
815
816 impl Thing {
817 fn new() -> Thing { Thing { x: 0 } }
818 }
819}
820
821fn main() { let foo_test = wrapper::Thing::new<|>(); }
822"#,
823 expect![[r#"
824 *new*
825 ```rust
826 wrapper::Thing
827 ```
828
829 ```rust
830 fn new() -> Thing
831 ```
832 "#]],
833 )
834 }
835
836 #[test]
837 fn test_hover_infer_associated_const_in_pattern() {
838 check(
839 r#"
840struct X;
841impl X {
842 const C: u32 = 1;
843}
844
845fn main() {
846 match 1 {
847 X::C<|> => {},
848 2 => {},
849 _ => {}
850 };
851}
852"#,
853 expect![[r#"
854 *C*
855 ```rust
856 const C: u32 = 1
857 ```
858 "#]],
859 )
860 }
861
862 #[test]
863 fn test_hover_self() {
864 check(
865 r#"
866struct Thing { x: u32 }
867impl Thing {
868 fn new() -> Self { Self<|> { x: 0 } }
869}
870"#,
871 expect![[r#"
872 *Self { x: 0 }*
873 ```rust
874 Thing
875 ```
876 "#]],
877 )
878 } /* FIXME: revive these tests
879 let (analysis, position) = analysis_and_position(
880 "
881 struct Thing { x: u32 }
882 impl Thing {
883 fn new() -> Self<|> {
884 Self { x: 0 }
885 }
886 }
887 ",
888 );
889
890 let hover = analysis.hover(position).unwrap().unwrap();
891 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
892
893 let (analysis, position) = analysis_and_position(
894 "
895 enum Thing { A }
896 impl Thing {
897 pub fn new() -> Self<|> {
898 Thing::A
899 }
900 }
901 ",
902 );
903 let hover = analysis.hover(position).unwrap().unwrap();
904 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
905
906 let (analysis, position) = analysis_and_position(
907 "
908 enum Thing { A }
909 impl Thing {
910 pub fn thing(a: Self<|>) {
911 }
912 }
913 ",
914 );
915 let hover = analysis.hover(position).unwrap().unwrap();
916 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
917 */
918
919 #[test]
920 fn test_hover_shadowing_pat() {
921 check(
922 r#"
923fn x() {}
924
925fn y() {
926 let x = 0i32;
927 x<|>;
928}
929"#,
930 expect![[r#"
931 *x*
932 ```rust
933 i32
934 ```
935 "#]],
936 )
937 }
938
939 #[test]
940 fn test_hover_macro_invocation() {
941 check(
942 r#"
943macro_rules! foo { () => {} }
944
945fn f() { fo<|>o!(); }
946"#,
947 expect![[r#"
948 *foo*
949 ```rust
950 macro_rules! foo
951 ```
952 "#]],
953 )
954 }
955
956 #[test]
957 fn test_hover_tuple_field() {
958 check(
959 r#"struct TS(String, i32<|>);"#,
960 expect![[r#"
961 *i32*
962 i32
963 "#]],
964 )
965 }
966
967 #[test]
968 fn test_hover_through_macro() {
969 check(
970 r#"
971macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
972fn foo() {}
973id! {
974 fn bar() { fo<|>o(); }
975}
976"#,
977 expect![[r#"
978 *foo*
979 ```rust
980 fn foo()
981 ```
982 "#]],
983 );
984 }
985
986 #[test]
987 fn test_hover_through_expr_in_macro() {
988 check(
989 r#"
990macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
991fn foo(bar:u32) { let a = id!(ba<|>r); }
992"#,
993 expect![[r#"
994 *bar*
995 ```rust
996 u32
997 ```
998 "#]],
999 );
1000 }
1001
1002 #[test]
1003 fn test_hover_through_expr_in_macro_recursive() {
1004 check(
1005 r#"
1006macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1007macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1008fn foo(bar:u32) { let a = id!(ba<|>r); }
1009"#,
1010 expect![[r#"
1011 *bar*
1012 ```rust
1013 u32
1014 ```
1015 "#]],
1016 );
1017 }
1018
1019 #[test]
1020 fn test_hover_through_func_in_macro_recursive() {
1021 check(
1022 r#"
1023macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1024macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1025fn bar() -> u32 { 0 }
1026fn foo() { let a = id!([0u32, bar(<|>)] ); }
1027"#,
1028 expect![[r#"
1029 *bar()*
1030 ```rust
1031 u32
1032 ```
1033 "#]],
1034 );
1035 }
1036
1037 #[test]
1038 fn test_hover_through_literal_string_in_macro() {
1039 check(
1040 r#"
1041macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
1042fn foo() {
1043 let mastered_for_itunes = "";
1044 let _ = arr!("Tr<|>acks", &mastered_for_itunes);
1045}
1046"#,
1047 expect![[r#"
1048 *"Tracks"*
1049 ```rust
1050 &str
1051 ```
1052 "#]],
1053 );
1054 }
1055
1056 #[test]
1057 fn test_hover_through_assert_macro() {
1058 check(
1059 r#"
1060#[rustc_builtin_macro]
1061macro_rules! assert {}
1062
1063fn bar() -> bool { true }
1064fn foo() {
1065 assert!(ba<|>r());
1066}
1067"#,
1068 expect![[r#"
1069 *bar*
1070 ```rust
1071 fn bar() -> bool
1072 ```
1073 "#]],
1074 );
1075 }
1076
1077 #[test]
1078 fn test_hover_through_literal_string_in_builtin_macro() {
1079 check_hover_no_result(
1080 r#"
1081 #[rustc_builtin_macro]
1082 macro_rules! format {}
1083
1084 fn foo() {
1085 format!("hel<|>lo {}", 0);
1086 }
1087 "#,
1088 );
1089 }
1090
1091 #[test]
1092 fn test_hover_non_ascii_space_doc() {
1093 check(
1094 "
1095/// <- `\u{3000}` here
1096fn foo() { }
1097
1098fn bar() { fo<|>o(); }
1099",
1100 expect![[r#"
1101 *foo*
1102 ```rust
1103 fn foo()
1104 ```
1105 ___
1106
1107 <- ` ` here
1108 "#]],
1109 );
1110 }
1111
1112 #[test]
1113 fn test_hover_function_show_qualifiers() {
1114 check(
1115 r#"async fn foo<|>() {}"#,
1116 expect![[r#"
1117 *foo*
1118 ```rust
1119 async fn foo()
1120 ```
1121 "#]],
1122 );
1123 check(
1124 r#"pub const unsafe fn foo<|>() {}"#,
1125 expect![[r#"
1126 *foo*
1127 ```rust
1128 pub const unsafe fn foo()
1129 ```
1130 "#]],
1131 );
1132 check(
1133 r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#,
1134 expect![[r#"
1135 *foo*
1136 ```rust
1137 pub(crate) async unsafe extern "C" fn foo()
1138 ```
1139 "#]],
1140 );
1141 }
1142
1143 #[test]
1144 fn test_hover_trait_show_qualifiers() {
1145 check_actions(
1146 r"unsafe trait foo<|>() {}",
1147 expect![[r#"
1148 [
1149 Implementaion(
1150 FilePosition {
1151 file_id: FileId(
1152 1,
1153 ),
1154 offset: 13,
1155 },
1156 ),
1157 ]
1158 "#]],
1159 );
1160 }
1161
1162 #[test]
1163 fn test_hover_extern_crate() {
1164 check(
1165 r#"
1166//- /main.rs
1167extern crate st<|>d;
1168//- /std/lib.rs
1169//! Standard library for this test
1170//!
1171//! Printed?
1172//! abc123
1173 "#,
1174 expect![[r#"
1175 *std*
1176 Standard library for this test
1177
1178 Printed?
1179 abc123
1180 "#]],
1181 );
1182 check(
1183 r#"
1184//- /main.rs
1185extern crate std as ab<|>c;
1186//- /std/lib.rs
1187//! Standard library for this test
1188//!
1189//! Printed?
1190//! abc123
1191 "#,
1192 expect![[r#"
1193 *abc*
1194 Standard library for this test
1195
1196 Printed?
1197 abc123
1198 "#]],
1199 );
1200 }
1201
1202 #[test]
1203 fn test_hover_mod_with_same_name_as_function() {
1204 check(
1205 r#"
1206use self::m<|>y::Bar;
1207mod my { pub struct Bar; }
1208
1209fn my() {}
1210"#,
1211 expect![[r#"
1212 *my*
1213 ```rust
1214 mod my
1215 ```
1216 "#]],
1217 );
1218 }
1219
1220 #[test]
1221 fn test_hover_struct_doc_comment() {
1222 check(
1223 r#"
1224/// bar docs
1225struct Bar;
1226
1227fn foo() { let bar = Ba<|>r; }
1228"#,
1229 expect![[r#"
1230 *Bar*
1231 ```rust
1232 struct Bar
1233 ```
1234 ___
1235
1236 bar docs
1237 "#]],
1238 );
1239 }
1240
1241 #[test]
1242 fn test_hover_struct_doc_attr() {
1243 check(
1244 r#"
1245#[doc = "bar docs"]
1246struct Bar;
1247
1248fn foo() { let bar = Ba<|>r; }
1249"#,
1250 expect![[r#"
1251 *Bar*
1252 ```rust
1253 struct Bar
1254 ```
1255 ___
1256
1257 bar docs
1258 "#]],
1259 );
1260 }
1261
1262 #[test]
1263 fn test_hover_struct_doc_attr_multiple_and_mixed() {
1264 check(
1265 r#"
1266/// bar docs 0
1267#[doc = "bar docs 1"]
1268#[doc = "bar docs 2"]
1269struct Bar;
1270
1271fn foo() { let bar = Ba<|>r; }
1272"#,
1273 expect![[r#"
1274 *Bar*
1275 ```rust
1276 struct Bar
1277 ```
1278 ___
1279
1280 bar docs 0
1281
1282 bar docs 1
1283
1284 bar docs 2
1285 "#]],
1286 );
1287 }
1288
1289 #[test]
1290 fn test_hover_macro_generated_struct_fn_doc_comment() {
1291 mark::check!(hover_macro_generated_struct_fn_doc_comment);
1292
1293 check(
1294 r#"
1295macro_rules! bar {
1296 () => {
1297 struct Bar;
1298 impl Bar {
1299 /// Do the foo
1300 fn foo(&self) {}
1301 }
1302 }
1303}
1304
1305bar!();
1306
1307fn foo() { let bar = Bar; bar.fo<|>o(); }
1308"#,
1309 expect![[r#"
1310 *foo*
1311 ```rust
1312 Bar
1313 ```
1314
1315 ```rust
1316 fn foo(&self)
1317 ```
1318 ___
1319
1320 Do the foo
1321 "#]],
1322 );
1323 }
1324
1325 #[test]
1326 fn test_hover_macro_generated_struct_fn_doc_attr() {
1327 mark::check!(hover_macro_generated_struct_fn_doc_attr);
1328
1329 check(
1330 r#"
1331macro_rules! bar {
1332 () => {
1333 struct Bar;
1334 impl Bar {
1335 #[doc = "Do the foo"]
1336 fn foo(&self) {}
1337 }
1338 }
1339}
1340
1341bar!();
1342
1343fn foo() { let bar = Bar; bar.fo<|>o(); }
1344"#,
1345 expect![[r#"
1346 *foo*
1347 ```rust
1348 Bar
1349 ```
1350
1351 ```rust
1352 fn foo(&self)
1353 ```
1354 ___
1355
1356 Do the foo
1357 "#]],
1358 );
1359 }
1360
1361 #[test]
1362 fn test_hover_trait_has_impl_action() {
1363 check_actions(
1364 r#"trait foo<|>() {}"#,
1365 expect![[r#"
1366 [
1367 Implementaion(
1368 FilePosition {
1369 file_id: FileId(
1370 1,
1371 ),
1372 offset: 6,
1373 },
1374 ),
1375 ]
1376 "#]],
1377 );
1378 }
1379
1380 #[test]
1381 fn test_hover_struct_has_impl_action() {
1382 check_actions(
1383 r"struct foo<|>() {}",
1384 expect![[r#"
1385 [
1386 Implementaion(
1387 FilePosition {
1388 file_id: FileId(
1389 1,
1390 ),
1391 offset: 7,
1392 },
1393 ),
1394 ]
1395 "#]],
1396 );
1397 }
1398
1399 #[test]
1400 fn test_hover_union_has_impl_action() {
1401 check_actions(
1402 r#"union foo<|>() {}"#,
1403 expect![[r#"
1404 [
1405 Implementaion(
1406 FilePosition {
1407 file_id: FileId(
1408 1,
1409 ),
1410 offset: 6,
1411 },
1412 ),
1413 ]
1414 "#]],
1415 );
1416 }
1417
1418 #[test]
1419 fn test_hover_enum_has_impl_action() {
1420 check_actions(
1421 r"enum foo<|>() { A, B }",
1422 expect![[r#"
1423 [
1424 Implementaion(
1425 FilePosition {
1426 file_id: FileId(
1427 1,
1428 ),
1429 offset: 5,
1430 },
1431 ),
1432 ]
1433 "#]],
1434 );
1435 }
1436
1437 #[test]
1438 fn test_hover_test_has_action() {
1439 check_actions(
1440 r#"
1441#[test]
1442fn foo_<|>test() {}
1443"#,
1444 expect![[r#"
1445 [
1446 Runnable(
1447 Runnable {
1448 nav: NavigationTarget {
1449 file_id: FileId(
1450 1,
1451 ),
1452 full_range: 0..24,
1453 focus_range: Some(
1454 11..19,
1455 ),
1456 name: "foo_test",
1457 kind: FN,
1458 container_name: None,
1459 description: None,
1460 docs: None,
1461 },
1462 kind: Test {
1463 test_id: Path(
1464 "foo_test",
1465 ),
1466 attr: TestAttr {
1467 ignore: false,
1468 },
1469 },
1470 cfg_exprs: [],
1471 },
1472 ),
1473 ]
1474 "#]],
1475 );
1476 }
1477
1478 #[test]
1479 fn test_hover_test_mod_has_action() {
1480 check_actions(
1481 r#"
1482mod tests<|> {
1483 #[test]
1484 fn foo_test() {}
1485}
1486"#,
1487 expect![[r#"
1488 [
1489 Runnable(
1490 Runnable {
1491 nav: NavigationTarget {
1492 file_id: FileId(
1493 1,
1494 ),
1495 full_range: 0..46,
1496 focus_range: Some(
1497 4..9,
1498 ),
1499 name: "tests",
1500 kind: MODULE,
1501 container_name: None,
1502 description: None,
1503 docs: None,
1504 },
1505 kind: TestMod {
1506 path: "tests",
1507 },
1508 cfg_exprs: [],
1509 },
1510 ),
1511 ]
1512 "#]],
1513 );
1514 }
1515
1516 #[test]
1517 fn test_hover_struct_has_goto_type_action() {
1518 check_actions(
1519 r#"
1520struct S{ f1: u32 }
1521
1522fn main() { let s<|>t = S{ f1:0 }; }
1523 "#,
1524 expect![[r#"
1525 [
1526 GoToType(
1527 [
1528 HoverGotoTypeData {
1529 mod_path: "S",
1530 nav: NavigationTarget {
1531 file_id: FileId(
1532 1,
1533 ),
1534 full_range: 0..19,
1535 focus_range: Some(
1536 7..8,
1537 ),
1538 name: "S",
1539 kind: STRUCT,
1540 container_name: None,
1541 description: Some(
1542 "struct S",
1543 ),
1544 docs: None,
1545 },
1546 },
1547 ],
1548 ),
1549 ]
1550 "#]],
1551 );
1552 }
1553
1554 #[test]
1555 fn test_hover_generic_struct_has_goto_type_actions() {
1556 check_actions(
1557 r#"
1558struct Arg(u32);
1559struct S<T>{ f1: T }
1560
1561fn main() { let s<|>t = S{ f1:Arg(0) }; }
1562"#,
1563 expect![[r#"
1564 [
1565 GoToType(
1566 [
1567 HoverGotoTypeData {
1568 mod_path: "S",
1569 nav: NavigationTarget {
1570 file_id: FileId(
1571 1,
1572 ),
1573 full_range: 17..37,
1574 focus_range: Some(
1575 24..25,
1576 ),
1577 name: "S",
1578 kind: STRUCT,
1579 container_name: None,
1580 description: Some(
1581 "struct S",
1582 ),
1583 docs: None,
1584 },
1585 },
1586 HoverGotoTypeData {
1587 mod_path: "Arg",
1588 nav: NavigationTarget {
1589 file_id: FileId(
1590 1,
1591 ),
1592 full_range: 0..16,
1593 focus_range: Some(
1594 7..10,
1595 ),
1596 name: "Arg",
1597 kind: STRUCT,
1598 container_name: None,
1599 description: Some(
1600 "struct Arg",
1601 ),
1602 docs: None,
1603 },
1604 },
1605 ],
1606 ),
1607 ]
1608 "#]],
1609 );
1610 }
1611
1612 #[test]
1613 fn test_hover_generic_struct_has_flattened_goto_type_actions() {
1614 check_actions(
1615 r#"
1616struct Arg(u32);
1617struct S<T>{ f1: T }
1618
1619fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
1620 "#,
1621 expect![[r#"
1622 [
1623 GoToType(
1624 [
1625 HoverGotoTypeData {
1626 mod_path: "S",
1627 nav: NavigationTarget {
1628 file_id: FileId(
1629 1,
1630 ),
1631 full_range: 17..37,
1632 focus_range: Some(
1633 24..25,
1634 ),
1635 name: "S",
1636 kind: STRUCT,
1637 container_name: None,
1638 description: Some(
1639 "struct S",
1640 ),
1641 docs: None,
1642 },
1643 },
1644 HoverGotoTypeData {
1645 mod_path: "Arg",
1646 nav: NavigationTarget {
1647 file_id: FileId(
1648 1,
1649 ),
1650 full_range: 0..16,
1651 focus_range: Some(
1652 7..10,
1653 ),
1654 name: "Arg",
1655 kind: STRUCT,
1656 container_name: None,
1657 description: Some(
1658 "struct Arg",
1659 ),
1660 docs: None,
1661 },
1662 },
1663 ],
1664 ),
1665 ]
1666 "#]],
1667 );
1668 }
1669
1670 #[test]
1671 fn test_hover_tuple_has_goto_type_actions() {
1672 check_actions(
1673 r#"
1674struct A(u32);
1675struct B(u32);
1676mod M {
1677 pub struct C(u32);
1678}
1679
1680fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
1681"#,
1682 expect![[r#"
1683 [
1684 GoToType(
1685 [
1686 HoverGotoTypeData {
1687 mod_path: "A",
1688 nav: NavigationTarget {
1689 file_id: FileId(
1690 1,
1691 ),
1692 full_range: 0..14,
1693 focus_range: Some(
1694 7..8,
1695 ),
1696 name: "A",
1697 kind: STRUCT,
1698 container_name: None,
1699 description: Some(
1700 "struct A",
1701 ),
1702 docs: None,
1703 },
1704 },
1705 HoverGotoTypeData {
1706 mod_path: "B",
1707 nav: NavigationTarget {
1708 file_id: FileId(
1709 1,
1710 ),
1711 full_range: 15..29,
1712 focus_range: Some(
1713 22..23,
1714 ),
1715 name: "B",
1716 kind: STRUCT,
1717 container_name: None,
1718 description: Some(
1719 "struct B",
1720 ),
1721 docs: None,
1722 },
1723 },
1724 HoverGotoTypeData {
1725 mod_path: "M::C",
1726 nav: NavigationTarget {
1727 file_id: FileId(
1728 1,
1729 ),
1730 full_range: 42..60,
1731 focus_range: Some(
1732 53..54,
1733 ),
1734 name: "C",
1735 kind: STRUCT,
1736 container_name: None,
1737 description: Some(
1738 "pub struct C",
1739 ),
1740 docs: None,
1741 },
1742 },
1743 ],
1744 ),
1745 ]
1746 "#]],
1747 );
1748 }
1749
1750 #[test]
1751 fn test_hover_return_impl_trait_has_goto_type_action() {
1752 check_actions(
1753 r#"
1754trait Foo {}
1755fn foo() -> impl Foo {}
1756
1757fn main() { let s<|>t = foo(); }
1758"#,
1759 expect![[r#"
1760 [
1761 GoToType(
1762 [
1763 HoverGotoTypeData {
1764 mod_path: "Foo",
1765 nav: NavigationTarget {
1766 file_id: FileId(
1767 1,
1768 ),
1769 full_range: 0..12,
1770 focus_range: Some(
1771 6..9,
1772 ),
1773 name: "Foo",
1774 kind: TRAIT,
1775 container_name: None,
1776 description: Some(
1777 "trait Foo",
1778 ),
1779 docs: None,
1780 },
1781 },
1782 ],
1783 ),
1784 ]
1785 "#]],
1786 );
1787 }
1788
1789 #[test]
1790 fn test_hover_generic_return_impl_trait_has_goto_type_action() {
1791 check_actions(
1792 r#"
1793trait Foo<T> {}
1794struct S;
1795fn foo() -> impl Foo<S> {}
1796
1797fn main() { let s<|>t = foo(); }
1798"#,
1799 expect![[r#"
1800 [
1801 GoToType(
1802 [
1803 HoverGotoTypeData {
1804 mod_path: "Foo",
1805 nav: NavigationTarget {
1806 file_id: FileId(
1807 1,
1808 ),
1809 full_range: 0..15,
1810 focus_range: Some(
1811 6..9,
1812 ),
1813 name: "Foo",
1814 kind: TRAIT,
1815 container_name: None,
1816 description: Some(
1817 "trait Foo",
1818 ),
1819 docs: None,
1820 },
1821 },
1822 HoverGotoTypeData {
1823 mod_path: "S",
1824 nav: NavigationTarget {
1825 file_id: FileId(
1826 1,
1827 ),
1828 full_range: 16..25,
1829 focus_range: Some(
1830 23..24,
1831 ),
1832 name: "S",
1833 kind: STRUCT,
1834 container_name: None,
1835 description: Some(
1836 "struct S",
1837 ),
1838 docs: None,
1839 },
1840 },
1841 ],
1842 ),
1843 ]
1844 "#]],
1845 );
1846 }
1847
1848 #[test]
1849 fn test_hover_return_impl_traits_has_goto_type_action() {
1850 check_actions(
1851 r#"
1852trait Foo {}
1853trait Bar {}
1854fn foo() -> impl Foo + Bar {}
1855
1856fn main() { let s<|>t = foo(); }
1857 "#,
1858 expect![[r#"
1859 [
1860 GoToType(
1861 [
1862 HoverGotoTypeData {
1863 mod_path: "Foo",
1864 nav: NavigationTarget {
1865 file_id: FileId(
1866 1,
1867 ),
1868 full_range: 0..12,
1869 focus_range: Some(
1870 6..9,
1871 ),
1872 name: "Foo",
1873 kind: TRAIT,
1874 container_name: None,
1875 description: Some(
1876 "trait Foo",
1877 ),
1878 docs: None,
1879 },
1880 },
1881 HoverGotoTypeData {
1882 mod_path: "Bar",
1883 nav: NavigationTarget {
1884 file_id: FileId(
1885 1,
1886 ),
1887 full_range: 13..25,
1888 focus_range: Some(
1889 19..22,
1890 ),
1891 name: "Bar",
1892 kind: TRAIT,
1893 container_name: None,
1894 description: Some(
1895 "trait Bar",
1896 ),
1897 docs: None,
1898 },
1899 },
1900 ],
1901 ),
1902 ]
1903 "#]],
1904 );
1905 }
1906
1907 #[test]
1908 fn test_hover_generic_return_impl_traits_has_goto_type_action() {
1909 check_actions(
1910 r#"
1911trait Foo<T> {}
1912trait Bar<T> {}
1913struct S1 {}
1914struct S2 {}
1915
1916fn foo() -> impl Foo<S1> + Bar<S2> {}
1917
1918fn main() { let s<|>t = foo(); }
1919"#,
1920 expect![[r#"
1921 [
1922 GoToType(
1923 [
1924 HoverGotoTypeData {
1925 mod_path: "Foo",
1926 nav: NavigationTarget {
1927 file_id: FileId(
1928 1,
1929 ),
1930 full_range: 0..15,
1931 focus_range: Some(
1932 6..9,
1933 ),
1934 name: "Foo",
1935 kind: TRAIT,
1936 container_name: None,
1937 description: Some(
1938 "trait Foo",
1939 ),
1940 docs: None,
1941 },
1942 },
1943 HoverGotoTypeData {
1944 mod_path: "Bar",
1945 nav: NavigationTarget {
1946 file_id: FileId(
1947 1,
1948 ),
1949 full_range: 16..31,
1950 focus_range: Some(
1951 22..25,
1952 ),
1953 name: "Bar",
1954 kind: TRAIT,
1955 container_name: None,
1956 description: Some(
1957 "trait Bar",
1958 ),
1959 docs: None,
1960 },
1961 },
1962 HoverGotoTypeData {
1963 mod_path: "S1",
1964 nav: NavigationTarget {
1965 file_id: FileId(
1966 1,
1967 ),
1968 full_range: 32..44,
1969 focus_range: Some(
1970 39..41,
1971 ),
1972 name: "S1",
1973 kind: STRUCT,
1974 container_name: None,
1975 description: Some(
1976 "struct S1",
1977 ),
1978 docs: None,
1979 },
1980 },
1981 HoverGotoTypeData {
1982 mod_path: "S2",
1983 nav: NavigationTarget {
1984 file_id: FileId(
1985 1,
1986 ),
1987 full_range: 45..57,
1988 focus_range: Some(
1989 52..54,
1990 ),
1991 name: "S2",
1992 kind: STRUCT,
1993 container_name: None,
1994 description: Some(
1995 "struct S2",
1996 ),
1997 docs: None,
1998 },
1999 },
2000 ],
2001 ),
2002 ]
2003 "#]],
2004 );
2005 }
2006
2007 #[test]
2008 fn test_hover_arg_impl_trait_has_goto_type_action() {
2009 check_actions(
2010 r#"
2011trait Foo {}
2012fn foo(ar<|>g: &impl Foo) {}
2013"#,
2014 expect![[r#"
2015 [
2016 GoToType(
2017 [
2018 HoverGotoTypeData {
2019 mod_path: "Foo",
2020 nav: NavigationTarget {
2021 file_id: FileId(
2022 1,
2023 ),
2024 full_range: 0..12,
2025 focus_range: Some(
2026 6..9,
2027 ),
2028 name: "Foo",
2029 kind: TRAIT,
2030 container_name: None,
2031 description: Some(
2032 "trait Foo",
2033 ),
2034 docs: None,
2035 },
2036 },
2037 ],
2038 ),
2039 ]
2040 "#]],
2041 );
2042 }
2043
2044 #[test]
2045 fn test_hover_arg_impl_traits_has_goto_type_action() {
2046 check_actions(
2047 r#"
2048trait Foo {}
2049trait Bar<T> {}
2050struct S{}
2051
2052fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2053"#,
2054 expect![[r#"
2055 [
2056 GoToType(
2057 [
2058 HoverGotoTypeData {
2059 mod_path: "Foo",
2060 nav: NavigationTarget {
2061 file_id: FileId(
2062 1,
2063 ),
2064 full_range: 0..12,
2065 focus_range: Some(
2066 6..9,
2067 ),
2068 name: "Foo",
2069 kind: TRAIT,
2070 container_name: None,
2071 description: Some(
2072 "trait Foo",
2073 ),
2074 docs: None,
2075 },
2076 },
2077 HoverGotoTypeData {
2078 mod_path: "Bar",
2079 nav: NavigationTarget {
2080 file_id: FileId(
2081 1,
2082 ),
2083 full_range: 13..28,
2084 focus_range: Some(
2085 19..22,
2086 ),
2087 name: "Bar",
2088 kind: TRAIT,
2089 container_name: None,
2090 description: Some(
2091 "trait Bar",
2092 ),
2093 docs: None,
2094 },
2095 },
2096 HoverGotoTypeData {
2097 mod_path: "S",
2098 nav: NavigationTarget {
2099 file_id: FileId(
2100 1,
2101 ),
2102 full_range: 29..39,
2103 focus_range: Some(
2104 36..37,
2105 ),
2106 name: "S",
2107 kind: STRUCT,
2108 container_name: None,
2109 description: Some(
2110 "struct S",
2111 ),
2112 docs: None,
2113 },
2114 },
2115 ],
2116 ),
2117 ]
2118 "#]],
2119 );
2120 }
2121
2122 #[test]
2123 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
2124 check_actions(
2125 r#"
2126trait Foo<T> {}
2127struct S {}
2128fn foo(ar<|>g: &impl Foo<S>) {}
2129"#,
2130 expect![[r#"
2131 [
2132 GoToType(
2133 [
2134 HoverGotoTypeData {
2135 mod_path: "Foo",
2136 nav: NavigationTarget {
2137 file_id: FileId(
2138 1,
2139 ),
2140 full_range: 0..15,
2141 focus_range: Some(
2142 6..9,
2143 ),
2144 name: "Foo",
2145 kind: TRAIT,
2146 container_name: None,
2147 description: Some(
2148 "trait Foo",
2149 ),
2150 docs: None,
2151 },
2152 },
2153 HoverGotoTypeData {
2154 mod_path: "S",
2155 nav: NavigationTarget {
2156 file_id: FileId(
2157 1,
2158 ),
2159 full_range: 16..27,
2160 focus_range: Some(
2161 23..24,
2162 ),
2163 name: "S",
2164 kind: STRUCT,
2165 container_name: None,
2166 description: Some(
2167 "struct S",
2168 ),
2169 docs: None,
2170 },
2171 },
2172 ],
2173 ),
2174 ]
2175 "#]],
2176 );
2177 }
2178
2179 #[test]
2180 fn test_hover_dyn_return_has_goto_type_action() {
2181 check_actions(
2182 r#"
2183trait Foo {}
2184struct S;
2185impl Foo for S {}
2186
2187struct B<T>{}
2188fn foo() -> B<dyn Foo> {}
2189
2190fn main() { let s<|>t = foo(); }
2191"#,
2192 expect![[r#"
2193 [
2194 GoToType(
2195 [
2196 HoverGotoTypeData {
2197 mod_path: "B",
2198 nav: NavigationTarget {
2199 file_id: FileId(
2200 1,
2201 ),
2202 full_range: 42..55,
2203 focus_range: Some(
2204 49..50,
2205 ),
2206 name: "B",
2207 kind: STRUCT,
2208 container_name: None,
2209 description: Some(
2210 "struct B",
2211 ),
2212 docs: None,
2213 },
2214 },
2215 HoverGotoTypeData {
2216 mod_path: "Foo",
2217 nav: NavigationTarget {
2218 file_id: FileId(
2219 1,
2220 ),
2221 full_range: 0..12,
2222 focus_range: Some(
2223 6..9,
2224 ),
2225 name: "Foo",
2226 kind: TRAIT,
2227 container_name: None,
2228 description: Some(
2229 "trait Foo",
2230 ),
2231 docs: None,
2232 },
2233 },
2234 ],
2235 ),
2236 ]
2237 "#]],
2238 );
2239 }
2240
2241 #[test]
2242 fn test_hover_dyn_arg_has_goto_type_action() {
2243 check_actions(
2244 r#"
2245trait Foo {}
2246fn foo(ar<|>g: &dyn Foo) {}
2247"#,
2248 expect![[r#"
2249 [
2250 GoToType(
2251 [
2252 HoverGotoTypeData {
2253 mod_path: "Foo",
2254 nav: NavigationTarget {
2255 file_id: FileId(
2256 1,
2257 ),
2258 full_range: 0..12,
2259 focus_range: Some(
2260 6..9,
2261 ),
2262 name: "Foo",
2263 kind: TRAIT,
2264 container_name: None,
2265 description: Some(
2266 "trait Foo",
2267 ),
2268 docs: None,
2269 },
2270 },
2271 ],
2272 ),
2273 ]
2274 "#]],
2275 );
2276 }
2277
2278 #[test]
2279 fn test_hover_generic_dyn_arg_has_goto_type_action() {
2280 check_actions(
2281 r#"
2282trait Foo<T> {}
2283struct S {}
2284fn foo(ar<|>g: &dyn Foo<S>) {}
2285"#,
2286 expect![[r#"
2287 [
2288 GoToType(
2289 [
2290 HoverGotoTypeData {
2291 mod_path: "Foo",
2292 nav: NavigationTarget {
2293 file_id: FileId(
2294 1,
2295 ),
2296 full_range: 0..15,
2297 focus_range: Some(
2298 6..9,
2299 ),
2300 name: "Foo",
2301 kind: TRAIT,
2302 container_name: None,
2303 description: Some(
2304 "trait Foo",
2305 ),
2306 docs: None,
2307 },
2308 },
2309 HoverGotoTypeData {
2310 mod_path: "S",
2311 nav: NavigationTarget {
2312 file_id: FileId(
2313 1,
2314 ),
2315 full_range: 16..27,
2316 focus_range: Some(
2317 23..24,
2318 ),
2319 name: "S",
2320 kind: STRUCT,
2321 container_name: None,
2322 description: Some(
2323 "struct S",
2324 ),
2325 docs: None,
2326 },
2327 },
2328 ],
2329 ),
2330 ]
2331 "#]],
2332 );
2333 }
2334
2335 #[test]
2336 fn test_hover_goto_type_action_links_order() {
2337 check_actions(
2338 r#"
2339trait ImplTrait<T> {}
2340trait DynTrait<T> {}
2341struct B<T> {}
2342struct S {}
2343
2344fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2345 "#,
2346 expect![[r#"
2347 [
2348 GoToType(
2349 [
2350 HoverGotoTypeData {
2351 mod_path: "ImplTrait",
2352 nav: NavigationTarget {
2353 file_id: FileId(
2354 1,
2355 ),
2356 full_range: 0..21,
2357 focus_range: Some(
2358 6..15,
2359 ),
2360 name: "ImplTrait",
2361 kind: TRAIT,
2362 container_name: None,
2363 description: Some(
2364 "trait ImplTrait",
2365 ),
2366 docs: None,
2367 },
2368 },
2369 HoverGotoTypeData {
2370 mod_path: "B",
2371 nav: NavigationTarget {
2372 file_id: FileId(
2373 1,
2374 ),
2375 full_range: 43..57,
2376 focus_range: Some(
2377 50..51,
2378 ),
2379 name: "B",
2380 kind: STRUCT,
2381 container_name: None,
2382 description: Some(
2383 "struct B",
2384 ),
2385 docs: None,
2386 },
2387 },
2388 HoverGotoTypeData {
2389 mod_path: "DynTrait",
2390 nav: NavigationTarget {
2391 file_id: FileId(
2392 1,
2393 ),
2394 full_range: 22..42,
2395 focus_range: Some(
2396 28..36,
2397 ),
2398 name: "DynTrait",
2399 kind: TRAIT,
2400 container_name: None,
2401 description: Some(
2402 "trait DynTrait",
2403 ),
2404 docs: None,
2405 },
2406 },
2407 HoverGotoTypeData {
2408 mod_path: "S",
2409 nav: NavigationTarget {
2410 file_id: FileId(
2411 1,
2412 ),
2413 full_range: 58..69,
2414 focus_range: Some(
2415 65..66,
2416 ),
2417 name: "S",
2418 kind: STRUCT,
2419 container_name: None,
2420 description: Some(
2421 "struct S",
2422 ),
2423 docs: None,
2424 },
2425 },
2426 ],
2427 ),
2428 ]
2429 "#]],
2430 );
2431 }
2432
2433 #[test]
2434 fn test_hover_associated_type_has_goto_type_action() {
2435 check_actions(
2436 r#"
2437trait Foo {
2438 type Item;
2439 fn get(self) -> Self::Item {}
2440}
2441
2442struct Bar{}
2443struct S{}
2444
2445impl Foo for S { type Item = Bar; }
2446
2447fn test() -> impl Foo { S {} }
2448
2449fn main() { let s<|>t = test().get(); }
2450"#,
2451 expect![[r#"
2452 [
2453 GoToType(
2454 [
2455 HoverGotoTypeData {
2456 mod_path: "Foo",
2457 nav: NavigationTarget {
2458 file_id: FileId(
2459 1,
2460 ),
2461 full_range: 0..62,
2462 focus_range: Some(
2463 6..9,
2464 ),
2465 name: "Foo",
2466 kind: TRAIT,
2467 container_name: None,
2468 description: Some(
2469 "trait Foo",
2470 ),
2471 docs: None,
2472 },
2473 },
2474 ],
2475 ),
2476 ]
2477 "#]],
2478 );
2479 }
2480}