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