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