diff options
author | Mikhail Rakhmanov <[email protected]> | 2020-06-13 07:42:15 +0100 |
---|---|---|
committer | Mikhail Rakhmanov <[email protected]> | 2020-06-13 07:42:15 +0100 |
commit | 16bbf4ab7f132e6e5e5318dccdef9a5d71afdd7f (patch) | |
tree | 4b79fa8c046be56b02427ba843e70cdf3ac05767 /crates/ra_ide/src/hover.rs | |
parent | eeb8b9e236796da8734ba81a49164864497f7226 (diff) | |
parent | b56ad148db0c69eb279c225f45d324b4e80e7367 (diff) |
Merge branch 'master' into keyword_completion
# Conflicts:
# docs/user/generated_features.adoc
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r-- | crates/ra_ide/src/hover.rs | 411 |
1 files changed, 385 insertions, 26 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index d96cb5596..ad78b7671 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use std::iter::once; | 1 | use std::iter::once; |
2 | 2 | ||
3 | use hir::{ | 3 | use hir::{ |
4 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, | 4 | Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, |
5 | ModuleSource, Semantics, | 5 | ModuleDef, ModuleSource, Semantics, |
6 | }; | 6 | }; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use ra_db::SourceDatabase; | 8 | use ra_db::SourceDatabase; |
@@ -10,22 +10,55 @@ use ra_ide_db::{ | |||
10 | defs::{classify_name, classify_name_ref, Definition}, | 10 | defs::{classify_name, classify_name_ref, Definition}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use ra_syntax::{ | 13 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; |
14 | ast::{self, DocCommentsOwner}, | ||
15 | match_ast, AstNode, | ||
16 | SyntaxKind::*, | ||
17 | SyntaxToken, TokenAtOffset, | ||
18 | }; | ||
19 | 14 | ||
20 | use crate::{ | 15 | use crate::{ |
21 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, |
22 | FilePosition, RangeInfo, | 17 | runnables::runnable, |
18 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | ||
23 | }; | 19 | }; |
20 | use test_utils::mark; | ||
21 | |||
22 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
23 | pub struct HoverConfig { | ||
24 | pub implementations: bool, | ||
25 | pub run: bool, | ||
26 | pub debug: bool, | ||
27 | } | ||
28 | |||
29 | impl Default for HoverConfig { | ||
30 | fn default() -> Self { | ||
31 | Self { implementations: true, run: true, debug: true } | ||
32 | } | ||
33 | } | ||
34 | |||
35 | impl HoverConfig { | ||
36 | pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false }; | ||
37 | |||
38 | pub fn any(&self) -> bool { | ||
39 | self.implementations || self.runnable() | ||
40 | } | ||
41 | |||
42 | pub fn none(&self) -> bool { | ||
43 | !self.any() | ||
44 | } | ||
45 | |||
46 | pub fn runnable(&self) -> bool { | ||
47 | self.run || self.debug | ||
48 | } | ||
49 | } | ||
50 | |||
51 | #[derive(Debug, Clone)] | ||
52 | pub enum HoverAction { | ||
53 | Runnable(Runnable), | ||
54 | Implementaion(FilePosition), | ||
55 | } | ||
24 | 56 | ||
25 | /// Contains the results when hovering over an item | 57 | /// Contains the results when hovering over an item |
26 | #[derive(Debug, Default)] | 58 | #[derive(Debug, Default)] |
27 | pub struct HoverResult { | 59 | pub struct HoverResult { |
28 | results: Vec<String>, | 60 | results: Vec<String>, |
61 | actions: Vec<HoverAction>, | ||
29 | } | 62 | } |
30 | 63 | ||
31 | impl HoverResult { | 64 | impl HoverResult { |
@@ -53,10 +86,20 @@ impl HoverResult { | |||
53 | &self.results | 86 | &self.results |
54 | } | 87 | } |
55 | 88 | ||
89 | pub fn actions(&self) -> &[HoverAction] { | ||
90 | &self.actions | ||
91 | } | ||
92 | |||
93 | pub fn push_action(&mut self, action: HoverAction) { | ||
94 | self.actions.push(action); | ||
95 | } | ||
96 | |||
56 | /// Returns the results converted into markup | 97 | /// Returns the results converted into markup |
57 | /// for displaying in a UI | 98 | /// for displaying in a UI |
99 | /// | ||
100 | /// Does not process actions! | ||
58 | pub fn to_markup(&self) -> String { | 101 | pub fn to_markup(&self) -> String { |
59 | self.results.join("\n\n---\n") | 102 | self.results.join("\n\n___\n") |
60 | } | 103 | } |
61 | } | 104 | } |
62 | 105 | ||
@@ -87,6 +130,14 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
87 | res.extend(hover_text_from_name_kind(db, name_kind)); | 130 | res.extend(hover_text_from_name_kind(db, name_kind)); |
88 | 131 | ||
89 | if !res.is_empty() { | 132 | if !res.is_empty() { |
133 | if let Some(action) = show_implementations_action(db, name_kind) { | ||
134 | res.push_action(action); | ||
135 | } | ||
136 | |||
137 | if let Some(action) = runnable_action(&sema, name_kind, position.file_id) { | ||
138 | res.push_action(action); | ||
139 | } | ||
140 | |||
90 | return Some(RangeInfo::new(range, res)); | 141 | return Some(RangeInfo::new(range, res)); |
91 | } | 142 | } |
92 | } | 143 | } |
@@ -117,6 +168,56 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
117 | Some(RangeInfo::new(range, res)) | 168 | Some(RangeInfo::new(range, res)) |
118 | } | 169 | } |
119 | 170 | ||
171 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | ||
172 | fn to_action(nav_target: NavigationTarget) -> HoverAction { | ||
173 | HoverAction::Implementaion(FilePosition { | ||
174 | file_id: nav_target.file_id(), | ||
175 | offset: nav_target.range().start(), | ||
176 | }) | ||
177 | } | ||
178 | |||
179 | match def { | ||
180 | Definition::ModuleDef(it) => match it { | ||
181 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), | ||
182 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), | ||
183 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), | ||
184 | ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), | ||
185 | _ => None, | ||
186 | }, | ||
187 | _ => None, | ||
188 | } | ||
189 | } | ||
190 | |||
191 | fn runnable_action( | ||
192 | sema: &Semantics<RootDatabase>, | ||
193 | def: Definition, | ||
194 | file_id: FileId, | ||
195 | ) -> Option<HoverAction> { | ||
196 | match def { | ||
197 | Definition::ModuleDef(it) => match it { | ||
198 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | ||
199 | ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id) | ||
200 | .map(|it| HoverAction::Runnable(it)), | ||
201 | _ => None, | ||
202 | }, | ||
203 | ModuleDef::Function(it) => { | ||
204 | let src = it.source(sema.db); | ||
205 | if src.file_id != file_id.into() { | ||
206 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | ||
207 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | ||
208 | |||
209 | return None; | ||
210 | } | ||
211 | |||
212 | runnable(&sema, src.value.syntax().clone(), file_id) | ||
213 | .map(|it| HoverAction::Runnable(it)) | ||
214 | } | ||
215 | _ => None, | ||
216 | }, | ||
217 | _ => None, | ||
218 | } | ||
219 | } | ||
220 | |||
120 | fn hover_text( | 221 | fn hover_text( |
121 | docs: Option<String>, | 222 | docs: Option<String>, |
122 | desc: Option<String>, | 223 | desc: Option<String>, |
@@ -169,13 +270,15 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
169 | return match def { | 270 | return match def { |
170 | Definition::Macro(it) => { | 271 | Definition::Macro(it) => { |
171 | let src = it.source(db); | 272 | let src = it.source(db); |
172 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path) | 273 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
274 | hover_text(docs, Some(macro_label(&src.value)), mod_path) | ||
173 | } | 275 | } |
174 | Definition::Field(it) => { | 276 | Definition::Field(it) => { |
175 | let src = it.source(db); | 277 | let src = it.source(db); |
176 | match src.value { | 278 | match src.value { |
177 | FieldSource::Named(it) => { | 279 | FieldSource::Named(it) => { |
178 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | 280 | let docs = Documentation::from_ast(&it).map(Into::into); |
281 | hover_text(docs, it.short_label(), mod_path) | ||
179 | } | 282 | } |
180 | _ => None, | 283 | _ => None, |
181 | } | 284 | } |
@@ -183,7 +286,8 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
183 | Definition::ModuleDef(it) => match it { | 286 | Definition::ModuleDef(it) => match it { |
184 | ModuleDef::Module(it) => match it.definition_source(db).value { | 287 | ModuleDef::Module(it) => match it.definition_source(db).value { |
185 | ModuleSource::Module(it) => { | 288 | ModuleSource::Module(it) => { |
186 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | 289 | let docs = Documentation::from_ast(&it).map(Into::into); |
290 | hover_text(docs, it.short_label(), mod_path) | ||
187 | } | 291 | } |
188 | _ => None, | 292 | _ => None, |
189 | }, | 293 | }, |
@@ -208,10 +312,11 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
208 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> | 312 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> |
209 | where | 313 | where |
210 | D: HasSource<Ast = A>, | 314 | D: HasSource<Ast = A>, |
211 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | 315 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, |
212 | { | 316 | { |
213 | let src = def.source(db); | 317 | let src = def.source(db); |
214 | hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path) | 318 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
319 | hover_text(docs, src.value.short_label(), mod_path) | ||
215 | } | 320 | } |
216 | } | 321 | } |
217 | 322 | ||
@@ -229,6 +334,9 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
229 | 334 | ||
230 | #[cfg(test)] | 335 | #[cfg(test)] |
231 | mod tests { | 336 | mod tests { |
337 | use super::*; | ||
338 | use insta::assert_debug_snapshot; | ||
339 | |||
232 | use ra_db::FileLoader; | 340 | use ra_db::FileLoader; |
233 | use ra_syntax::TextRange; | 341 | use ra_syntax::TextRange; |
234 | 342 | ||
@@ -242,7 +350,15 @@ mod tests { | |||
242 | s.map(trim_markup) | 350 | s.map(trim_markup) |
243 | } | 351 | } |
244 | 352 | ||
245 | fn check_hover_result(fixture: &str, expected: &[&str]) -> String { | 353 | fn assert_impl_action(action: &HoverAction, position: u32) { |
354 | let offset = match action { | ||
355 | HoverAction::Implementaion(pos) => pos.offset, | ||
356 | it => panic!("Unexpected hover action: {:#?}", it), | ||
357 | }; | ||
358 | assert_eq!(offset, position.into()); | ||
359 | } | ||
360 | |||
361 | fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) { | ||
246 | let (analysis, position) = analysis_and_position(fixture); | 362 | let (analysis, position) = analysis_and_position(fixture); |
247 | let hover = analysis.hover(position).unwrap().unwrap(); | 363 | let hover = analysis.hover(position).unwrap().unwrap(); |
248 | let mut results = Vec::from(hover.info.results()); | 364 | let mut results = Vec::from(hover.info.results()); |
@@ -257,7 +373,7 @@ mod tests { | |||
257 | assert_eq!(hover.info.len(), expected.len()); | 373 | assert_eq!(hover.info.len(), expected.len()); |
258 | 374 | ||
259 | let content = analysis.db.file_text(position.file_id); | 375 | let content = analysis.db.file_text(position.file_id); |
260 | content[hover.range].to_string() | 376 | (content[hover.range].to_string(), hover.info.actions().to_vec()) |
261 | } | 377 | } |
262 | 378 | ||
263 | fn check_hover_no_result(fixture: &str) { | 379 | fn check_hover_no_result(fixture: &str) { |
@@ -458,7 +574,7 @@ struct Test<K, T = u8> { | |||
458 | } | 574 | } |
459 | 575 | ||
460 | fn main() { | 576 | fn main() { |
461 | let zz<|> = Test { t: 23, k: 33 }; | 577 | let zz<|> = Test { t: 23u8, k: 33 }; |
462 | }"#, | 578 | }"#, |
463 | &["Test<i32, u8>"], | 579 | &["Test<i32, u8>"], |
464 | ); | 580 | ); |
@@ -747,7 +863,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
747 | 863 | ||
748 | #[test] | 864 | #[test] |
749 | fn test_hover_through_macro() { | 865 | fn test_hover_through_macro() { |
750 | let hover_on = check_hover_result( | 866 | let (hover_on, _) = check_hover_result( |
751 | " | 867 | " |
752 | //- /lib.rs | 868 | //- /lib.rs |
753 | macro_rules! id { | 869 | macro_rules! id { |
@@ -768,7 +884,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
768 | 884 | ||
769 | #[test] | 885 | #[test] |
770 | fn test_hover_through_expr_in_macro() { | 886 | fn test_hover_through_expr_in_macro() { |
771 | let hover_on = check_hover_result( | 887 | let (hover_on, _) = check_hover_result( |
772 | " | 888 | " |
773 | //- /lib.rs | 889 | //- /lib.rs |
774 | macro_rules! id { | 890 | macro_rules! id { |
@@ -786,7 +902,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
786 | 902 | ||
787 | #[test] | 903 | #[test] |
788 | fn test_hover_through_expr_in_macro_recursive() { | 904 | fn test_hover_through_expr_in_macro_recursive() { |
789 | let hover_on = check_hover_result( | 905 | let (hover_on, _) = check_hover_result( |
790 | " | 906 | " |
791 | //- /lib.rs | 907 | //- /lib.rs |
792 | macro_rules! id_deep { | 908 | macro_rules! id_deep { |
@@ -807,7 +923,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
807 | 923 | ||
808 | #[test] | 924 | #[test] |
809 | fn test_hover_through_func_in_macro_recursive() { | 925 | fn test_hover_through_func_in_macro_recursive() { |
810 | let hover_on = check_hover_result( | 926 | let (hover_on, _) = check_hover_result( |
811 | " | 927 | " |
812 | //- /lib.rs | 928 | //- /lib.rs |
813 | macro_rules! id_deep { | 929 | macro_rules! id_deep { |
@@ -831,7 +947,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
831 | 947 | ||
832 | #[test] | 948 | #[test] |
833 | fn test_hover_through_literal_string_in_macro() { | 949 | fn test_hover_through_literal_string_in_macro() { |
834 | let hover_on = check_hover_result( | 950 | let (hover_on, _) = check_hover_result( |
835 | r#" | 951 | r#" |
836 | //- /lib.rs | 952 | //- /lib.rs |
837 | macro_rules! arr { | 953 | macro_rules! arr { |
@@ -850,7 +966,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
850 | 966 | ||
851 | #[test] | 967 | #[test] |
852 | fn test_hover_through_assert_macro() { | 968 | fn test_hover_through_assert_macro() { |
853 | let hover_on = check_hover_result( | 969 | let (hover_on, _) = check_hover_result( |
854 | r#" | 970 | r#" |
855 | //- /lib.rs | 971 | //- /lib.rs |
856 | #[rustc_builtin_macro] | 972 | #[rustc_builtin_macro] |
@@ -926,13 +1042,14 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
926 | 1042 | ||
927 | #[test] | 1043 | #[test] |
928 | fn test_hover_trait_show_qualifiers() { | 1044 | fn test_hover_trait_show_qualifiers() { |
929 | check_hover_result( | 1045 | let (_, actions) = check_hover_result( |
930 | " | 1046 | " |
931 | //- /lib.rs | 1047 | //- /lib.rs |
932 | unsafe trait foo<|>() {} | 1048 | unsafe trait foo<|>() {} |
933 | ", | 1049 | ", |
934 | &["unsafe trait foo"], | 1050 | &["unsafe trait foo"], |
935 | ); | 1051 | ); |
1052 | assert_impl_action(&actions[0], 13); | ||
936 | } | 1053 | } |
937 | 1054 | ||
938 | #[test] | 1055 | #[test] |
@@ -951,4 +1068,246 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
951 | &["mod my"], | 1068 | &["mod my"], |
952 | ); | 1069 | ); |
953 | } | 1070 | } |
1071 | |||
1072 | #[test] | ||
1073 | fn test_hover_struct_doc_comment() { | ||
1074 | check_hover_result( | ||
1075 | r#" | ||
1076 | //- /lib.rs | ||
1077 | /// bar docs | ||
1078 | struct Bar; | ||
1079 | |||
1080 | fn foo() { | ||
1081 | let bar = Ba<|>r; | ||
1082 | } | ||
1083 | "#, | ||
1084 | &["struct Bar\n```\n___\n\nbar docs"], | ||
1085 | ); | ||
1086 | } | ||
1087 | |||
1088 | #[test] | ||
1089 | fn test_hover_struct_doc_attr() { | ||
1090 | check_hover_result( | ||
1091 | r#" | ||
1092 | //- /lib.rs | ||
1093 | #[doc = "bar docs"] | ||
1094 | struct Bar; | ||
1095 | |||
1096 | fn foo() { | ||
1097 | let bar = Ba<|>r; | ||
1098 | } | ||
1099 | "#, | ||
1100 | &["struct Bar\n```\n___\n\nbar docs"], | ||
1101 | ); | ||
1102 | } | ||
1103 | |||
1104 | #[test] | ||
1105 | fn test_hover_struct_doc_attr_multiple_and_mixed() { | ||
1106 | check_hover_result( | ||
1107 | r#" | ||
1108 | //- /lib.rs | ||
1109 | /// bar docs 0 | ||
1110 | #[doc = "bar docs 1"] | ||
1111 | #[doc = "bar docs 2"] | ||
1112 | struct Bar; | ||
1113 | |||
1114 | fn foo() { | ||
1115 | let bar = Ba<|>r; | ||
1116 | } | ||
1117 | "#, | ||
1118 | &["struct Bar\n```\n___\n\nbar docs 0\n\nbar docs 1\n\nbar docs 2"], | ||
1119 | ); | ||
1120 | } | ||
1121 | |||
1122 | #[test] | ||
1123 | fn test_hover_macro_generated_struct_fn_doc_comment() { | ||
1124 | mark::check!(hover_macro_generated_struct_fn_doc_comment); | ||
1125 | |||
1126 | check_hover_result( | ||
1127 | r#" | ||
1128 | //- /lib.rs | ||
1129 | macro_rules! bar { | ||
1130 | () => { | ||
1131 | struct Bar; | ||
1132 | impl Bar { | ||
1133 | /// Do the foo | ||
1134 | fn foo(&self) {} | ||
1135 | } | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | bar!(); | ||
1140 | |||
1141 | fn foo() { | ||
1142 | let bar = Bar; | ||
1143 | bar.fo<|>o(); | ||
1144 | } | ||
1145 | "#, | ||
1146 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\n Do the foo"], | ||
1147 | ); | ||
1148 | } | ||
1149 | |||
1150 | #[test] | ||
1151 | fn test_hover_macro_generated_struct_fn_doc_attr() { | ||
1152 | mark::check!(hover_macro_generated_struct_fn_doc_attr); | ||
1153 | |||
1154 | check_hover_result( | ||
1155 | r#" | ||
1156 | //- /lib.rs | ||
1157 | macro_rules! bar { | ||
1158 | () => { | ||
1159 | struct Bar; | ||
1160 | impl Bar { | ||
1161 | #[doc = "Do the foo"] | ||
1162 | fn foo(&self) {} | ||
1163 | } | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1167 | bar!(); | ||
1168 | |||
1169 | fn foo() { | ||
1170 | let bar = Bar; | ||
1171 | bar.fo<|>o(); | ||
1172 | } | ||
1173 | "#, | ||
1174 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], | ||
1175 | ); | ||
1176 | } | ||
1177 | |||
1178 | #[test] | ||
1179 | fn test_hover_trait_has_impl_action() { | ||
1180 | let (_, actions) = check_hover_result( | ||
1181 | " | ||
1182 | //- /lib.rs | ||
1183 | trait foo<|>() {} | ||
1184 | ", | ||
1185 | &["trait foo"], | ||
1186 | ); | ||
1187 | assert_impl_action(&actions[0], 6); | ||
1188 | } | ||
1189 | |||
1190 | #[test] | ||
1191 | fn test_hover_struct_has_impl_action() { | ||
1192 | let (_, actions) = check_hover_result( | ||
1193 | " | ||
1194 | //- /lib.rs | ||
1195 | struct foo<|>() {} | ||
1196 | ", | ||
1197 | &["struct foo"], | ||
1198 | ); | ||
1199 | assert_impl_action(&actions[0], 7); | ||
1200 | } | ||
1201 | |||
1202 | #[test] | ||
1203 | fn test_hover_union_has_impl_action() { | ||
1204 | let (_, actions) = check_hover_result( | ||
1205 | " | ||
1206 | //- /lib.rs | ||
1207 | union foo<|>() {} | ||
1208 | ", | ||
1209 | &["union foo"], | ||
1210 | ); | ||
1211 | assert_impl_action(&actions[0], 6); | ||
1212 | } | ||
1213 | |||
1214 | #[test] | ||
1215 | fn test_hover_enum_has_impl_action() { | ||
1216 | let (_, actions) = check_hover_result( | ||
1217 | " | ||
1218 | //- /lib.rs | ||
1219 | enum foo<|>() { | ||
1220 | A, | ||
1221 | B | ||
1222 | } | ||
1223 | ", | ||
1224 | &["enum foo"], | ||
1225 | ); | ||
1226 | assert_impl_action(&actions[0], 5); | ||
1227 | } | ||
1228 | |||
1229 | #[test] | ||
1230 | fn test_hover_test_has_action() { | ||
1231 | let (_, actions) = check_hover_result( | ||
1232 | " | ||
1233 | //- /lib.rs | ||
1234 | #[test] | ||
1235 | fn foo_<|>test() {} | ||
1236 | ", | ||
1237 | &["fn foo_test()"], | ||
1238 | ); | ||
1239 | assert_debug_snapshot!(actions, | ||
1240 | @r###" | ||
1241 | [ | ||
1242 | Runnable( | ||
1243 | Runnable { | ||
1244 | nav: NavigationTarget { | ||
1245 | file_id: FileId( | ||
1246 | 1, | ||
1247 | ), | ||
1248 | full_range: 0..24, | ||
1249 | name: "foo_test", | ||
1250 | kind: FN_DEF, | ||
1251 | focus_range: Some( | ||
1252 | 11..19, | ||
1253 | ), | ||
1254 | container_name: None, | ||
1255 | description: None, | ||
1256 | docs: None, | ||
1257 | }, | ||
1258 | kind: Test { | ||
1259 | test_id: Path( | ||
1260 | "foo_test", | ||
1261 | ), | ||
1262 | attr: TestAttr { | ||
1263 | ignore: false, | ||
1264 | }, | ||
1265 | }, | ||
1266 | cfg_exprs: [], | ||
1267 | }, | ||
1268 | ), | ||
1269 | ] | ||
1270 | "###); | ||
1271 | } | ||
1272 | |||
1273 | #[test] | ||
1274 | fn test_hover_test_mod_has_action() { | ||
1275 | let (_, actions) = check_hover_result( | ||
1276 | " | ||
1277 | //- /lib.rs | ||
1278 | mod tests<|> { | ||
1279 | #[test] | ||
1280 | fn foo_test() {} | ||
1281 | } | ||
1282 | ", | ||
1283 | &["mod tests"], | ||
1284 | ); | ||
1285 | assert_debug_snapshot!(actions, | ||
1286 | @r###" | ||
1287 | [ | ||
1288 | Runnable( | ||
1289 | Runnable { | ||
1290 | nav: NavigationTarget { | ||
1291 | file_id: FileId( | ||
1292 | 1, | ||
1293 | ), | ||
1294 | full_range: 0..46, | ||
1295 | name: "tests", | ||
1296 | kind: MODULE, | ||
1297 | focus_range: Some( | ||
1298 | 4..9, | ||
1299 | ), | ||
1300 | container_name: None, | ||
1301 | description: None, | ||
1302 | docs: None, | ||
1303 | }, | ||
1304 | kind: TestMod { | ||
1305 | path: "tests", | ||
1306 | }, | ||
1307 | cfg_exprs: [], | ||
1308 | }, | ||
1309 | ), | ||
1310 | ] | ||
1311 | "###); | ||
1312 | } | ||
954 | } | 1313 | } |