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