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.rs2461
1 files changed, 0 insertions, 2461 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
deleted file mode 100644
index 331aa4db0..000000000
--- a/crates/ra_ide/src/hover.rs
+++ /dev/null
@@ -1,2461 +0,0 @@
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 test_hover_infer_associated_method_result() {
771 check(
772 r#"
773struct Thing { x: u32 }
774
775impl Thing {
776 fn new() -> Thing { Thing { x: 0 } }
777}
778
779fn main() { let foo_<|>test = Thing::new(); }
780 "#,
781 expect![[r#"
782 *foo_test*
783 ```rust
784 Thing
785 ```
786 "#]],
787 )
788 }
789
790 #[test]
791 fn test_hover_infer_associated_method_exact() {
792 check(
793 r#"
794mod wrapper {
795 struct Thing { x: u32 }
796
797 impl Thing {
798 fn new() -> Thing { Thing { x: 0 } }
799 }
800}
801
802fn main() { let foo_test = wrapper::Thing::new<|>(); }
803"#,
804 expect![[r#"
805 *new*
806 ```rust
807 wrapper::Thing
808 ```
809
810 ```rust
811 fn new() -> Thing
812 ```
813 "#]],
814 )
815 }
816
817 #[test]
818 fn test_hover_infer_associated_const_in_pattern() {
819 check(
820 r#"
821struct X;
822impl X {
823 const C: u32 = 1;
824}
825
826fn main() {
827 match 1 {
828 X::C<|> => {},
829 2 => {},
830 _ => {}
831 };
832}
833"#,
834 expect![[r#"
835 *C*
836 ```rust
837 const C: u32 = 1
838 ```
839 "#]],
840 )
841 }
842
843 #[test]
844 fn test_hover_self() {
845 check(
846 r#"
847struct Thing { x: u32 }
848impl Thing {
849 fn new() -> Self { Self<|> { x: 0 } }
850}
851"#,
852 expect![[r#"
853 *Self { x: 0 }*
854 ```rust
855 Thing
856 ```
857 "#]],
858 )
859 } /* FIXME: revive these tests
860 let (analysis, position) = analysis_and_position(
861 "
862 struct Thing { x: u32 }
863 impl Thing {
864 fn new() -> Self<|> {
865 Self { x: 0 }
866 }
867 }
868 ",
869 );
870
871 let hover = analysis.hover(position).unwrap().unwrap();
872 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
873
874 let (analysis, position) = analysis_and_position(
875 "
876 enum Thing { A }
877 impl Thing {
878 pub fn new() -> Self<|> {
879 Thing::A
880 }
881 }
882 ",
883 );
884 let hover = analysis.hover(position).unwrap().unwrap();
885 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
886
887 let (analysis, position) = analysis_and_position(
888 "
889 enum Thing { A }
890 impl Thing {
891 pub fn thing(a: Self<|>) {
892 }
893 }
894 ",
895 );
896 let hover = analysis.hover(position).unwrap().unwrap();
897 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
898 */
899
900 #[test]
901 fn test_hover_shadowing_pat() {
902 check(
903 r#"
904fn x() {}
905
906fn y() {
907 let x = 0i32;
908 x<|>;
909}
910"#,
911 expect![[r#"
912 *x*
913 ```rust
914 i32
915 ```
916 "#]],
917 )
918 }
919
920 #[test]
921 fn test_hover_macro_invocation() {
922 check(
923 r#"
924macro_rules! foo { () => {} }
925
926fn f() { fo<|>o!(); }
927"#,
928 expect![[r#"
929 *foo*
930 ```rust
931 macro_rules! foo
932 ```
933 "#]],
934 )
935 }
936
937 #[test]
938 fn test_hover_tuple_field() {
939 check(
940 r#"struct TS(String, i32<|>);"#,
941 expect![[r#"
942 *i32*
943 i32
944 "#]],
945 )
946 }
947
948 #[test]
949 fn test_hover_through_macro() {
950 check(
951 r#"
952macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
953fn foo() {}
954id! {
955 fn bar() { fo<|>o(); }
956}
957"#,
958 expect![[r#"
959 *foo*
960 ```rust
961 fn foo()
962 ```
963 "#]],
964 );
965 }
966
967 #[test]
968 fn test_hover_through_expr_in_macro() {
969 check(
970 r#"
971macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
972fn foo(bar:u32) { let a = id!(ba<|>r); }
973"#,
974 expect![[r#"
975 *bar*
976 ```rust
977 u32
978 ```
979 "#]],
980 );
981 }
982
983 #[test]
984 fn test_hover_through_expr_in_macro_recursive() {
985 check(
986 r#"
987macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
988macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
989fn foo(bar:u32) { let a = id!(ba<|>r); }
990"#,
991 expect![[r#"
992 *bar*
993 ```rust
994 u32
995 ```
996 "#]],
997 );
998 }
999
1000 #[test]
1001 fn test_hover_through_func_in_macro_recursive() {
1002 check(
1003 r#"
1004macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1005macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1006fn bar() -> u32 { 0 }
1007fn foo() { let a = id!([0u32, bar(<|>)] ); }
1008"#,
1009 expect![[r#"
1010 *bar()*
1011 ```rust
1012 u32
1013 ```
1014 "#]],
1015 );
1016 }
1017
1018 #[test]
1019 fn test_hover_through_literal_string_in_macro() {
1020 check(
1021 r#"
1022macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
1023fn foo() {
1024 let mastered_for_itunes = "";
1025 let _ = arr!("Tr<|>acks", &mastered_for_itunes);
1026}
1027"#,
1028 expect![[r#"
1029 *"Tracks"*
1030 ```rust
1031 &str
1032 ```
1033 "#]],
1034 );
1035 }
1036
1037 #[test]
1038 fn test_hover_through_assert_macro() {
1039 check(
1040 r#"
1041#[rustc_builtin_macro]
1042macro_rules! assert {}
1043
1044fn bar() -> bool { true }
1045fn foo() {
1046 assert!(ba<|>r());
1047}
1048"#,
1049 expect![[r#"
1050 *bar*
1051 ```rust
1052 fn bar() -> bool
1053 ```
1054 "#]],
1055 );
1056 }
1057
1058 #[test]
1059 fn test_hover_through_literal_string_in_builtin_macro() {
1060 check_hover_no_result(
1061 r#"
1062 #[rustc_builtin_macro]
1063 macro_rules! format {}
1064
1065 fn foo() {
1066 format!("hel<|>lo {}", 0);
1067 }
1068 "#,
1069 );
1070 }
1071
1072 #[test]
1073 fn test_hover_non_ascii_space_doc() {
1074 check(
1075 "
1076/// <- `\u{3000}` here
1077fn foo() { }
1078
1079fn bar() { fo<|>o(); }
1080",
1081 expect![[r#"
1082 *foo*
1083 ```rust
1084 fn foo()
1085 ```
1086 ___
1087
1088 <- ` ` here
1089 "#]],
1090 );
1091 }
1092
1093 #[test]
1094 fn test_hover_function_show_qualifiers() {
1095 check(
1096 r#"async fn foo<|>() {}"#,
1097 expect![[r#"
1098 *foo*
1099 ```rust
1100 async fn foo()
1101 ```
1102 "#]],
1103 );
1104 check(
1105 r#"pub const unsafe fn foo<|>() {}"#,
1106 expect![[r#"
1107 *foo*
1108 ```rust
1109 pub const unsafe fn foo()
1110 ```
1111 "#]],
1112 );
1113 check(
1114 r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#,
1115 expect![[r#"
1116 *foo*
1117 ```rust
1118 pub(crate) async unsafe extern "C" fn foo()
1119 ```
1120 "#]],
1121 );
1122 }
1123
1124 #[test]
1125 fn test_hover_trait_show_qualifiers() {
1126 check_actions(
1127 r"unsafe trait foo<|>() {}",
1128 expect![[r#"
1129 [
1130 Implementaion(
1131 FilePosition {
1132 file_id: FileId(
1133 1,
1134 ),
1135 offset: 13,
1136 },
1137 ),
1138 ]
1139 "#]],
1140 );
1141 }
1142
1143 #[test]
1144 fn test_hover_extern_crate() {
1145 check(
1146 r#"
1147//- /main.rs
1148extern crate st<|>d;
1149//- /std/lib.rs
1150//! Standard library for this test
1151//!
1152//! Printed?
1153//! abc123
1154 "#,
1155 expect![[r#"
1156 *std*
1157 Standard library for this test
1158
1159 Printed?
1160 abc123
1161 "#]],
1162 );
1163 check(
1164 r#"
1165//- /main.rs
1166extern crate std as ab<|>c;
1167//- /std/lib.rs
1168//! Standard library for this test
1169//!
1170//! Printed?
1171//! abc123
1172 "#,
1173 expect![[r#"
1174 *abc*
1175 Standard library for this test
1176
1177 Printed?
1178 abc123
1179 "#]],
1180 );
1181 }
1182
1183 #[test]
1184 fn test_hover_mod_with_same_name_as_function() {
1185 check(
1186 r#"
1187use self::m<|>y::Bar;
1188mod my { pub struct Bar; }
1189
1190fn my() {}
1191"#,
1192 expect![[r#"
1193 *my*
1194 ```rust
1195 mod my
1196 ```
1197 "#]],
1198 );
1199 }
1200
1201 #[test]
1202 fn test_hover_struct_doc_comment() {
1203 check(
1204 r#"
1205/// bar docs
1206struct Bar;
1207
1208fn foo() { let bar = Ba<|>r; }
1209"#,
1210 expect![[r#"
1211 *Bar*
1212 ```rust
1213 struct Bar
1214 ```
1215 ___
1216
1217 bar docs
1218 "#]],
1219 );
1220 }
1221
1222 #[test]
1223 fn test_hover_struct_doc_attr() {
1224 check(
1225 r#"
1226#[doc = "bar docs"]
1227struct Bar;
1228
1229fn foo() { let bar = Ba<|>r; }
1230"#,
1231 expect![[r#"
1232 *Bar*
1233 ```rust
1234 struct Bar
1235 ```
1236 ___
1237
1238 bar docs
1239 "#]],
1240 );
1241 }
1242
1243 #[test]
1244 fn test_hover_struct_doc_attr_multiple_and_mixed() {
1245 check(
1246 r#"
1247/// bar docs 0
1248#[doc = "bar docs 1"]
1249#[doc = "bar docs 2"]
1250struct Bar;
1251
1252fn foo() { let bar = Ba<|>r; }
1253"#,
1254 expect![[r#"
1255 *Bar*
1256 ```rust
1257 struct Bar
1258 ```
1259 ___
1260
1261 bar docs 0
1262
1263 bar docs 1
1264
1265 bar docs 2
1266 "#]],
1267 );
1268 }
1269
1270 #[test]
1271 fn test_hover_macro_generated_struct_fn_doc_comment() {
1272 mark::check!(hover_macro_generated_struct_fn_doc_comment);
1273
1274 check(
1275 r#"
1276macro_rules! bar {
1277 () => {
1278 struct Bar;
1279 impl Bar {
1280 /// Do the foo
1281 fn foo(&self) {}
1282 }
1283 }
1284}
1285
1286bar!();
1287
1288fn foo() { let bar = Bar; bar.fo<|>o(); }
1289"#,
1290 expect![[r#"
1291 *foo*
1292 ```rust
1293 Bar
1294 ```
1295
1296 ```rust
1297 fn foo(&self)
1298 ```
1299 ___
1300
1301 Do the foo
1302 "#]],
1303 );
1304 }
1305
1306 #[test]
1307 fn test_hover_macro_generated_struct_fn_doc_attr() {
1308 mark::check!(hover_macro_generated_struct_fn_doc_attr);
1309
1310 check(
1311 r#"
1312macro_rules! bar {
1313 () => {
1314 struct Bar;
1315 impl Bar {
1316 #[doc = "Do the foo"]
1317 fn foo(&self) {}
1318 }
1319 }
1320}
1321
1322bar!();
1323
1324fn foo() { let bar = Bar; bar.fo<|>o(); }
1325"#,
1326 expect![[r#"
1327 *foo*
1328 ```rust
1329 Bar
1330 ```
1331
1332 ```rust
1333 fn foo(&self)
1334 ```
1335 ___
1336
1337 Do the foo
1338 "#]],
1339 );
1340 }
1341
1342 #[test]
1343 fn test_hover_trait_has_impl_action() {
1344 check_actions(
1345 r#"trait foo<|>() {}"#,
1346 expect![[r#"
1347 [
1348 Implementaion(
1349 FilePosition {
1350 file_id: FileId(
1351 1,
1352 ),
1353 offset: 6,
1354 },
1355 ),
1356 ]
1357 "#]],
1358 );
1359 }
1360
1361 #[test]
1362 fn test_hover_struct_has_impl_action() {
1363 check_actions(
1364 r"struct foo<|>() {}",
1365 expect![[r#"
1366 [
1367 Implementaion(
1368 FilePosition {
1369 file_id: FileId(
1370 1,
1371 ),
1372 offset: 7,
1373 },
1374 ),
1375 ]
1376 "#]],
1377 );
1378 }
1379
1380 #[test]
1381 fn test_hover_union_has_impl_action() {
1382 check_actions(
1383 r#"union foo<|>() {}"#,
1384 expect![[r#"
1385 [
1386 Implementaion(
1387 FilePosition {
1388 file_id: FileId(
1389 1,
1390 ),
1391 offset: 6,
1392 },
1393 ),
1394 ]
1395 "#]],
1396 );
1397 }
1398
1399 #[test]
1400 fn test_hover_enum_has_impl_action() {
1401 check_actions(
1402 r"enum foo<|>() { A, B }",
1403 expect![[r#"
1404 [
1405 Implementaion(
1406 FilePosition {
1407 file_id: FileId(
1408 1,
1409 ),
1410 offset: 5,
1411 },
1412 ),
1413 ]
1414 "#]],
1415 );
1416 }
1417
1418 #[test]
1419 fn test_hover_test_has_action() {
1420 check_actions(
1421 r#"
1422#[test]
1423fn foo_<|>test() {}
1424"#,
1425 expect![[r#"
1426 [
1427 Runnable(
1428 Runnable {
1429 nav: NavigationTarget {
1430 file_id: FileId(
1431 1,
1432 ),
1433 full_range: 0..24,
1434 focus_range: Some(
1435 11..19,
1436 ),
1437 name: "foo_test",
1438 kind: FN,
1439 container_name: None,
1440 description: None,
1441 docs: None,
1442 },
1443 kind: Test {
1444 test_id: Path(
1445 "foo_test",
1446 ),
1447 attr: TestAttr {
1448 ignore: false,
1449 },
1450 },
1451 cfg_exprs: [],
1452 },
1453 ),
1454 ]
1455 "#]],
1456 );
1457 }
1458
1459 #[test]
1460 fn test_hover_test_mod_has_action() {
1461 check_actions(
1462 r#"
1463mod tests<|> {
1464 #[test]
1465 fn foo_test() {}
1466}
1467"#,
1468 expect![[r#"
1469 [
1470 Runnable(
1471 Runnable {
1472 nav: NavigationTarget {
1473 file_id: FileId(
1474 1,
1475 ),
1476 full_range: 0..46,
1477 focus_range: Some(
1478 4..9,
1479 ),
1480 name: "tests",
1481 kind: MODULE,
1482 container_name: None,
1483 description: None,
1484 docs: None,
1485 },
1486 kind: TestMod {
1487 path: "tests",
1488 },
1489 cfg_exprs: [],
1490 },
1491 ),
1492 ]
1493 "#]],
1494 );
1495 }
1496
1497 #[test]
1498 fn test_hover_struct_has_goto_type_action() {
1499 check_actions(
1500 r#"
1501struct S{ f1: u32 }
1502
1503fn main() { let s<|>t = S{ f1:0 }; }
1504 "#,
1505 expect![[r#"
1506 [
1507 GoToType(
1508 [
1509 HoverGotoTypeData {
1510 mod_path: "S",
1511 nav: NavigationTarget {
1512 file_id: FileId(
1513 1,
1514 ),
1515 full_range: 0..19,
1516 focus_range: Some(
1517 7..8,
1518 ),
1519 name: "S",
1520 kind: STRUCT,
1521 container_name: None,
1522 description: Some(
1523 "struct S",
1524 ),
1525 docs: None,
1526 },
1527 },
1528 ],
1529 ),
1530 ]
1531 "#]],
1532 );
1533 }
1534
1535 #[test]
1536 fn test_hover_generic_struct_has_goto_type_actions() {
1537 check_actions(
1538 r#"
1539struct Arg(u32);
1540struct S<T>{ f1: T }
1541
1542fn main() { let s<|>t = S{ f1:Arg(0) }; }
1543"#,
1544 expect![[r#"
1545 [
1546 GoToType(
1547 [
1548 HoverGotoTypeData {
1549 mod_path: "S",
1550 nav: NavigationTarget {
1551 file_id: FileId(
1552 1,
1553 ),
1554 full_range: 17..37,
1555 focus_range: Some(
1556 24..25,
1557 ),
1558 name: "S",
1559 kind: STRUCT,
1560 container_name: None,
1561 description: Some(
1562 "struct S",
1563 ),
1564 docs: None,
1565 },
1566 },
1567 HoverGotoTypeData {
1568 mod_path: "Arg",
1569 nav: NavigationTarget {
1570 file_id: FileId(
1571 1,
1572 ),
1573 full_range: 0..16,
1574 focus_range: Some(
1575 7..10,
1576 ),
1577 name: "Arg",
1578 kind: STRUCT,
1579 container_name: None,
1580 description: Some(
1581 "struct Arg",
1582 ),
1583 docs: None,
1584 },
1585 },
1586 ],
1587 ),
1588 ]
1589 "#]],
1590 );
1591 }
1592
1593 #[test]
1594 fn test_hover_generic_struct_has_flattened_goto_type_actions() {
1595 check_actions(
1596 r#"
1597struct Arg(u32);
1598struct S<T>{ f1: T }
1599
1600fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
1601 "#,
1602 expect![[r#"
1603 [
1604 GoToType(
1605 [
1606 HoverGotoTypeData {
1607 mod_path: "S",
1608 nav: NavigationTarget {
1609 file_id: FileId(
1610 1,
1611 ),
1612 full_range: 17..37,
1613 focus_range: Some(
1614 24..25,
1615 ),
1616 name: "S",
1617 kind: STRUCT,
1618 container_name: None,
1619 description: Some(
1620 "struct S",
1621 ),
1622 docs: None,
1623 },
1624 },
1625 HoverGotoTypeData {
1626 mod_path: "Arg",
1627 nav: NavigationTarget {
1628 file_id: FileId(
1629 1,
1630 ),
1631 full_range: 0..16,
1632 focus_range: Some(
1633 7..10,
1634 ),
1635 name: "Arg",
1636 kind: STRUCT,
1637 container_name: None,
1638 description: Some(
1639 "struct Arg",
1640 ),
1641 docs: None,
1642 },
1643 },
1644 ],
1645 ),
1646 ]
1647 "#]],
1648 );
1649 }
1650
1651 #[test]
1652 fn test_hover_tuple_has_goto_type_actions() {
1653 check_actions(
1654 r#"
1655struct A(u32);
1656struct B(u32);
1657mod M {
1658 pub struct C(u32);
1659}
1660
1661fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
1662"#,
1663 expect![[r#"
1664 [
1665 GoToType(
1666 [
1667 HoverGotoTypeData {
1668 mod_path: "A",
1669 nav: NavigationTarget {
1670 file_id: FileId(
1671 1,
1672 ),
1673 full_range: 0..14,
1674 focus_range: Some(
1675 7..8,
1676 ),
1677 name: "A",
1678 kind: STRUCT,
1679 container_name: None,
1680 description: Some(
1681 "struct A",
1682 ),
1683 docs: None,
1684 },
1685 },
1686 HoverGotoTypeData {
1687 mod_path: "B",
1688 nav: NavigationTarget {
1689 file_id: FileId(
1690 1,
1691 ),
1692 full_range: 15..29,
1693 focus_range: Some(
1694 22..23,
1695 ),
1696 name: "B",
1697 kind: STRUCT,
1698 container_name: None,
1699 description: Some(
1700 "struct B",
1701 ),
1702 docs: None,
1703 },
1704 },
1705 HoverGotoTypeData {
1706 mod_path: "M::C",
1707 nav: NavigationTarget {
1708 file_id: FileId(
1709 1,
1710 ),
1711 full_range: 42..60,
1712 focus_range: Some(
1713 53..54,
1714 ),
1715 name: "C",
1716 kind: STRUCT,
1717 container_name: None,
1718 description: Some(
1719 "pub struct C",
1720 ),
1721 docs: None,
1722 },
1723 },
1724 ],
1725 ),
1726 ]
1727 "#]],
1728 );
1729 }
1730
1731 #[test]
1732 fn test_hover_return_impl_trait_has_goto_type_action() {
1733 check_actions(
1734 r#"
1735trait Foo {}
1736fn foo() -> impl Foo {}
1737
1738fn main() { let s<|>t = foo(); }
1739"#,
1740 expect![[r#"
1741 [
1742 GoToType(
1743 [
1744 HoverGotoTypeData {
1745 mod_path: "Foo",
1746 nav: NavigationTarget {
1747 file_id: FileId(
1748 1,
1749 ),
1750 full_range: 0..12,
1751 focus_range: Some(
1752 6..9,
1753 ),
1754 name: "Foo",
1755 kind: TRAIT,
1756 container_name: None,
1757 description: Some(
1758 "trait Foo",
1759 ),
1760 docs: None,
1761 },
1762 },
1763 ],
1764 ),
1765 ]
1766 "#]],
1767 );
1768 }
1769
1770 #[test]
1771 fn test_hover_generic_return_impl_trait_has_goto_type_action() {
1772 check_actions(
1773 r#"
1774trait Foo<T> {}
1775struct S;
1776fn foo() -> impl Foo<S> {}
1777
1778fn main() { let s<|>t = foo(); }
1779"#,
1780 expect![[r#"
1781 [
1782 GoToType(
1783 [
1784 HoverGotoTypeData {
1785 mod_path: "Foo",
1786 nav: NavigationTarget {
1787 file_id: FileId(
1788 1,
1789 ),
1790 full_range: 0..15,
1791 focus_range: Some(
1792 6..9,
1793 ),
1794 name: "Foo",
1795 kind: TRAIT,
1796 container_name: None,
1797 description: Some(
1798 "trait Foo",
1799 ),
1800 docs: None,
1801 },
1802 },
1803 HoverGotoTypeData {
1804 mod_path: "S",
1805 nav: NavigationTarget {
1806 file_id: FileId(
1807 1,
1808 ),
1809 full_range: 16..25,
1810 focus_range: Some(
1811 23..24,
1812 ),
1813 name: "S",
1814 kind: STRUCT,
1815 container_name: None,
1816 description: Some(
1817 "struct S",
1818 ),
1819 docs: None,
1820 },
1821 },
1822 ],
1823 ),
1824 ]
1825 "#]],
1826 );
1827 }
1828
1829 #[test]
1830 fn test_hover_return_impl_traits_has_goto_type_action() {
1831 check_actions(
1832 r#"
1833trait Foo {}
1834trait Bar {}
1835fn foo() -> impl Foo + Bar {}
1836
1837fn main() { let s<|>t = foo(); }
1838 "#,
1839 expect![[r#"
1840 [
1841 GoToType(
1842 [
1843 HoverGotoTypeData {
1844 mod_path: "Foo",
1845 nav: NavigationTarget {
1846 file_id: FileId(
1847 1,
1848 ),
1849 full_range: 0..12,
1850 focus_range: Some(
1851 6..9,
1852 ),
1853 name: "Foo",
1854 kind: TRAIT,
1855 container_name: None,
1856 description: Some(
1857 "trait Foo",
1858 ),
1859 docs: None,
1860 },
1861 },
1862 HoverGotoTypeData {
1863 mod_path: "Bar",
1864 nav: NavigationTarget {
1865 file_id: FileId(
1866 1,
1867 ),
1868 full_range: 13..25,
1869 focus_range: Some(
1870 19..22,
1871 ),
1872 name: "Bar",
1873 kind: TRAIT,
1874 container_name: None,
1875 description: Some(
1876 "trait Bar",
1877 ),
1878 docs: None,
1879 },
1880 },
1881 ],
1882 ),
1883 ]
1884 "#]],
1885 );
1886 }
1887
1888 #[test]
1889 fn test_hover_generic_return_impl_traits_has_goto_type_action() {
1890 check_actions(
1891 r#"
1892trait Foo<T> {}
1893trait Bar<T> {}
1894struct S1 {}
1895struct S2 {}
1896
1897fn foo() -> impl Foo<S1> + Bar<S2> {}
1898
1899fn main() { let s<|>t = foo(); }
1900"#,
1901 expect![[r#"
1902 [
1903 GoToType(
1904 [
1905 HoverGotoTypeData {
1906 mod_path: "Foo",
1907 nav: NavigationTarget {
1908 file_id: FileId(
1909 1,
1910 ),
1911 full_range: 0..15,
1912 focus_range: Some(
1913 6..9,
1914 ),
1915 name: "Foo",
1916 kind: TRAIT,
1917 container_name: None,
1918 description: Some(
1919 "trait Foo",
1920 ),
1921 docs: None,
1922 },
1923 },
1924 HoverGotoTypeData {
1925 mod_path: "Bar",
1926 nav: NavigationTarget {
1927 file_id: FileId(
1928 1,
1929 ),
1930 full_range: 16..31,
1931 focus_range: Some(
1932 22..25,
1933 ),
1934 name: "Bar",
1935 kind: TRAIT,
1936 container_name: None,
1937 description: Some(
1938 "trait Bar",
1939 ),
1940 docs: None,
1941 },
1942 },
1943 HoverGotoTypeData {
1944 mod_path: "S1",
1945 nav: NavigationTarget {
1946 file_id: FileId(
1947 1,
1948 ),
1949 full_range: 32..44,
1950 focus_range: Some(
1951 39..41,
1952 ),
1953 name: "S1",
1954 kind: STRUCT,
1955 container_name: None,
1956 description: Some(
1957 "struct S1",
1958 ),
1959 docs: None,
1960 },
1961 },
1962 HoverGotoTypeData {
1963 mod_path: "S2",
1964 nav: NavigationTarget {
1965 file_id: FileId(
1966 1,
1967 ),
1968 full_range: 45..57,
1969 focus_range: Some(
1970 52..54,
1971 ),
1972 name: "S2",
1973 kind: STRUCT,
1974 container_name: None,
1975 description: Some(
1976 "struct S2",
1977 ),
1978 docs: None,
1979 },
1980 },
1981 ],
1982 ),
1983 ]
1984 "#]],
1985 );
1986 }
1987
1988 #[test]
1989 fn test_hover_arg_impl_trait_has_goto_type_action() {
1990 check_actions(
1991 r#"
1992trait Foo {}
1993fn foo(ar<|>g: &impl Foo) {}
1994"#,
1995 expect![[r#"
1996 [
1997 GoToType(
1998 [
1999 HoverGotoTypeData {
2000 mod_path: "Foo",
2001 nav: NavigationTarget {
2002 file_id: FileId(
2003 1,
2004 ),
2005 full_range: 0..12,
2006 focus_range: Some(
2007 6..9,
2008 ),
2009 name: "Foo",
2010 kind: TRAIT,
2011 container_name: None,
2012 description: Some(
2013 "trait Foo",
2014 ),
2015 docs: None,
2016 },
2017 },
2018 ],
2019 ),
2020 ]
2021 "#]],
2022 );
2023 }
2024
2025 #[test]
2026 fn test_hover_arg_impl_traits_has_goto_type_action() {
2027 check_actions(
2028 r#"
2029trait Foo {}
2030trait Bar<T> {}
2031struct S{}
2032
2033fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2034"#,
2035 expect![[r#"
2036 [
2037 GoToType(
2038 [
2039 HoverGotoTypeData {
2040 mod_path: "Foo",
2041 nav: NavigationTarget {
2042 file_id: FileId(
2043 1,
2044 ),
2045 full_range: 0..12,
2046 focus_range: Some(
2047 6..9,
2048 ),
2049 name: "Foo",
2050 kind: TRAIT,
2051 container_name: None,
2052 description: Some(
2053 "trait Foo",
2054 ),
2055 docs: None,
2056 },
2057 },
2058 HoverGotoTypeData {
2059 mod_path: "Bar",
2060 nav: NavigationTarget {
2061 file_id: FileId(
2062 1,
2063 ),
2064 full_range: 13..28,
2065 focus_range: Some(
2066 19..22,
2067 ),
2068 name: "Bar",
2069 kind: TRAIT,
2070 container_name: None,
2071 description: Some(
2072 "trait Bar",
2073 ),
2074 docs: None,
2075 },
2076 },
2077 HoverGotoTypeData {
2078 mod_path: "S",
2079 nav: NavigationTarget {
2080 file_id: FileId(
2081 1,
2082 ),
2083 full_range: 29..39,
2084 focus_range: Some(
2085 36..37,
2086 ),
2087 name: "S",
2088 kind: STRUCT,
2089 container_name: None,
2090 description: Some(
2091 "struct S",
2092 ),
2093 docs: None,
2094 },
2095 },
2096 ],
2097 ),
2098 ]
2099 "#]],
2100 );
2101 }
2102
2103 #[test]
2104 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
2105 check_actions(
2106 r#"
2107trait Foo<T> {}
2108struct S {}
2109fn foo(ar<|>g: &impl Foo<S>) {}
2110"#,
2111 expect![[r#"
2112 [
2113 GoToType(
2114 [
2115 HoverGotoTypeData {
2116 mod_path: "Foo",
2117 nav: NavigationTarget {
2118 file_id: FileId(
2119 1,
2120 ),
2121 full_range: 0..15,
2122 focus_range: Some(
2123 6..9,
2124 ),
2125 name: "Foo",
2126 kind: TRAIT,
2127 container_name: None,
2128 description: Some(
2129 "trait Foo",
2130 ),
2131 docs: None,
2132 },
2133 },
2134 HoverGotoTypeData {
2135 mod_path: "S",
2136 nav: NavigationTarget {
2137 file_id: FileId(
2138 1,
2139 ),
2140 full_range: 16..27,
2141 focus_range: Some(
2142 23..24,
2143 ),
2144 name: "S",
2145 kind: STRUCT,
2146 container_name: None,
2147 description: Some(
2148 "struct S",
2149 ),
2150 docs: None,
2151 },
2152 },
2153 ],
2154 ),
2155 ]
2156 "#]],
2157 );
2158 }
2159
2160 #[test]
2161 fn test_hover_dyn_return_has_goto_type_action() {
2162 check_actions(
2163 r#"
2164trait Foo {}
2165struct S;
2166impl Foo for S {}
2167
2168struct B<T>{}
2169fn foo() -> B<dyn Foo> {}
2170
2171fn main() { let s<|>t = foo(); }
2172"#,
2173 expect![[r#"
2174 [
2175 GoToType(
2176 [
2177 HoverGotoTypeData {
2178 mod_path: "B",
2179 nav: NavigationTarget {
2180 file_id: FileId(
2181 1,
2182 ),
2183 full_range: 42..55,
2184 focus_range: Some(
2185 49..50,
2186 ),
2187 name: "B",
2188 kind: STRUCT,
2189 container_name: None,
2190 description: Some(
2191 "struct B",
2192 ),
2193 docs: None,
2194 },
2195 },
2196 HoverGotoTypeData {
2197 mod_path: "Foo",
2198 nav: NavigationTarget {
2199 file_id: FileId(
2200 1,
2201 ),
2202 full_range: 0..12,
2203 focus_range: Some(
2204 6..9,
2205 ),
2206 name: "Foo",
2207 kind: TRAIT,
2208 container_name: None,
2209 description: Some(
2210 "trait Foo",
2211 ),
2212 docs: None,
2213 },
2214 },
2215 ],
2216 ),
2217 ]
2218 "#]],
2219 );
2220 }
2221
2222 #[test]
2223 fn test_hover_dyn_arg_has_goto_type_action() {
2224 check_actions(
2225 r#"
2226trait Foo {}
2227fn foo(ar<|>g: &dyn Foo) {}
2228"#,
2229 expect![[r#"
2230 [
2231 GoToType(
2232 [
2233 HoverGotoTypeData {
2234 mod_path: "Foo",
2235 nav: NavigationTarget {
2236 file_id: FileId(
2237 1,
2238 ),
2239 full_range: 0..12,
2240 focus_range: Some(
2241 6..9,
2242 ),
2243 name: "Foo",
2244 kind: TRAIT,
2245 container_name: None,
2246 description: Some(
2247 "trait Foo",
2248 ),
2249 docs: None,
2250 },
2251 },
2252 ],
2253 ),
2254 ]
2255 "#]],
2256 );
2257 }
2258
2259 #[test]
2260 fn test_hover_generic_dyn_arg_has_goto_type_action() {
2261 check_actions(
2262 r#"
2263trait Foo<T> {}
2264struct S {}
2265fn foo(ar<|>g: &dyn Foo<S>) {}
2266"#,
2267 expect![[r#"
2268 [
2269 GoToType(
2270 [
2271 HoverGotoTypeData {
2272 mod_path: "Foo",
2273 nav: NavigationTarget {
2274 file_id: FileId(
2275 1,
2276 ),
2277 full_range: 0..15,
2278 focus_range: Some(
2279 6..9,
2280 ),
2281 name: "Foo",
2282 kind: TRAIT,
2283 container_name: None,
2284 description: Some(
2285 "trait Foo",
2286 ),
2287 docs: None,
2288 },
2289 },
2290 HoverGotoTypeData {
2291 mod_path: "S",
2292 nav: NavigationTarget {
2293 file_id: FileId(
2294 1,
2295 ),
2296 full_range: 16..27,
2297 focus_range: Some(
2298 23..24,
2299 ),
2300 name: "S",
2301 kind: STRUCT,
2302 container_name: None,
2303 description: Some(
2304 "struct S",
2305 ),
2306 docs: None,
2307 },
2308 },
2309 ],
2310 ),
2311 ]
2312 "#]],
2313 );
2314 }
2315
2316 #[test]
2317 fn test_hover_goto_type_action_links_order() {
2318 check_actions(
2319 r#"
2320trait ImplTrait<T> {}
2321trait DynTrait<T> {}
2322struct B<T> {}
2323struct S {}
2324
2325fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2326 "#,
2327 expect![[r#"
2328 [
2329 GoToType(
2330 [
2331 HoverGotoTypeData {
2332 mod_path: "ImplTrait",
2333 nav: NavigationTarget {
2334 file_id: FileId(
2335 1,
2336 ),
2337 full_range: 0..21,
2338 focus_range: Some(
2339 6..15,
2340 ),
2341 name: "ImplTrait",
2342 kind: TRAIT,
2343 container_name: None,
2344 description: Some(
2345 "trait ImplTrait",
2346 ),
2347 docs: None,
2348 },
2349 },
2350 HoverGotoTypeData {
2351 mod_path: "B",
2352 nav: NavigationTarget {
2353 file_id: FileId(
2354 1,
2355 ),
2356 full_range: 43..57,
2357 focus_range: Some(
2358 50..51,
2359 ),
2360 name: "B",
2361 kind: STRUCT,
2362 container_name: None,
2363 description: Some(
2364 "struct B",
2365 ),
2366 docs: None,
2367 },
2368 },
2369 HoverGotoTypeData {
2370 mod_path: "DynTrait",
2371 nav: NavigationTarget {
2372 file_id: FileId(
2373 1,
2374 ),
2375 full_range: 22..42,
2376 focus_range: Some(
2377 28..36,
2378 ),
2379 name: "DynTrait",
2380 kind: TRAIT,
2381 container_name: None,
2382 description: Some(
2383 "trait DynTrait",
2384 ),
2385 docs: None,
2386 },
2387 },
2388 HoverGotoTypeData {
2389 mod_path: "S",
2390 nav: NavigationTarget {
2391 file_id: FileId(
2392 1,
2393 ),
2394 full_range: 58..69,
2395 focus_range: Some(
2396 65..66,
2397 ),
2398 name: "S",
2399 kind: STRUCT,
2400 container_name: None,
2401 description: Some(
2402 "struct S",
2403 ),
2404 docs: None,
2405 },
2406 },
2407 ],
2408 ),
2409 ]
2410 "#]],
2411 );
2412 }
2413
2414 #[test]
2415 fn test_hover_associated_type_has_goto_type_action() {
2416 check_actions(
2417 r#"
2418trait Foo {
2419 type Item;
2420 fn get(self) -> Self::Item {}
2421}
2422
2423struct Bar{}
2424struct S{}
2425
2426impl Foo for S { type Item = Bar; }
2427
2428fn test() -> impl Foo { S {} }
2429
2430fn main() { let s<|>t = test().get(); }
2431"#,
2432 expect![[r#"
2433 [
2434 GoToType(
2435 [
2436 HoverGotoTypeData {
2437 mod_path: "Foo",
2438 nav: NavigationTarget {
2439 file_id: FileId(
2440 1,
2441 ),
2442 full_range: 0..62,
2443 focus_range: Some(
2444 6..9,
2445 ),
2446 name: "Foo",
2447 kind: TRAIT,
2448 container_name: None,
2449 description: Some(
2450 "trait Foo",
2451 ),
2452 docs: None,
2453 },
2454 },
2455 ],
2456 ),
2457 ]
2458 "#]],
2459 );
2460 }
2461}