aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/pull_assignment_up.rs (renamed from crates/assists/src/handlers/extract_assignment.rs)54
-rw-r--r--crates/assists/src/lib.rs8
-rw-r--r--crates/assists/src/tests/generated.rs58
-rw-r--r--crates/hir/src/code_model.rs20
-rw-r--r--crates/hir_ty/src/display.rs2
-rw-r--r--crates/ide/src/display/short_label.rs11
-rw-r--r--crates/ide/src/hover.rs91
-rw-r--r--crates/rust-analyzer/src/handlers.rs2
8 files changed, 166 insertions, 80 deletions
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/pull_assignment_up.rs
index ae99598c0..560d93e10 100644
--- a/crates/assists/src/handlers/extract_assignment.rs
+++ b/crates/assists/src/handlers/pull_assignment_up.rs
@@ -9,9 +9,9 @@ use crate::{
9 AssistId, AssistKind, 9 AssistId, AssistKind,
10}; 10};
11 11
12// Assist: extract_assignment 12// Assist: pull_assignment_up
13// 13//
14// Extracts variable assigment to outside an if or match statement. 14// Extracts variable assignment to outside an if or match statement.
15// 15//
16// ``` 16// ```
17// fn main() { 17// fn main() {
@@ -36,7 +36,7 @@ use crate::{
36// }; 36// };
37// } 37// }
38// ``` 38// ```
39pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 39pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; 40 let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
41 let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { 41 let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment {
42 assign_expr.lhs()? 42 assign_expr.lhs()?
@@ -61,8 +61,8 @@ pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Optio
61 let expr_stmt = make::expr_stmt(new_stmt); 61 let expr_stmt = make::expr_stmt(new_stmt);
62 62
63 acc.add( 63 acc.add(
64 AssistId("extract_assignment", AssistKind::RefactorExtract), 64 AssistId("pull_assignment_up", AssistKind::RefactorExtract),
65 "Extract assignment", 65 "Pull assignment up",
66 old_stmt.syntax().text_range(), 66 old_stmt.syntax().text_range(),
67 move |edit| { 67 move |edit| {
68 edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); 68 edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt));
@@ -104,7 +104,7 @@ fn exprify_if(
104 ast::ElseBranch::Block(exprify_block(block, sema, name)?) 104 ast::ElseBranch::Block(exprify_block(block, sema, name)?)
105 } 105 }
106 ast::ElseBranch::IfExpr(expr) => { 106 ast::ElseBranch::IfExpr(expr) => {
107 mark::hit!(test_extract_assigment_chained_if); 107 mark::hit!(test_pull_assignment_up_chained_if);
108 ast::ElseBranch::IfExpr(ast::IfExpr::cast( 108 ast::ElseBranch::IfExpr(ast::IfExpr::cast(
109 exprify_if(&expr, sema, name)?.syntax().to_owned(), 109 exprify_if(&expr, sema, name)?.syntax().to_owned(),
110 )?) 110 )?)
@@ -144,7 +144,7 @@ fn is_equivalent(
144) -> bool { 144) -> bool {
145 match (expr0, expr1) { 145 match (expr0, expr1) {
146 (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { 146 (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => {
147 mark::hit!(test_extract_assignment_field_assignment); 147 mark::hit!(test_pull_assignment_up_field_assignment);
148 sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) 148 sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1)
149 } 149 }
150 (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { 150 (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => {
@@ -167,9 +167,9 @@ mod tests {
167 use crate::tests::{check_assist, check_assist_not_applicable}; 167 use crate::tests::{check_assist, check_assist_not_applicable};
168 168
169 #[test] 169 #[test]
170 fn test_extract_assignment_if() { 170 fn test_pull_assignment_up_if() {
171 check_assist( 171 check_assist(
172 extract_assigment, 172 pull_assignment_up,
173 r#" 173 r#"
174fn foo() { 174fn foo() {
175 let mut a = 1; 175 let mut a = 1;
@@ -194,9 +194,9 @@ fn foo() {
194 } 194 }
195 195
196 #[test] 196 #[test]
197 fn test_extract_assignment_match() { 197 fn test_pull_assignment_up_match() {
198 check_assist( 198 check_assist(
199 extract_assigment, 199 pull_assignment_up,
200 r#" 200 r#"
201fn foo() { 201fn foo() {
202 let mut a = 1; 202 let mut a = 1;
@@ -233,9 +233,9 @@ fn foo() {
233 } 233 }
234 234
235 #[test] 235 #[test]
236 fn test_extract_assignment_not_last_not_applicable() { 236 fn test_pull_assignment_up_not_last_not_applicable() {
237 check_assist_not_applicable( 237 check_assist_not_applicable(
238 extract_assigment, 238 pull_assignment_up,
239 r#" 239 r#"
240fn foo() { 240fn foo() {
241 let mut a = 1; 241 let mut a = 1;
@@ -251,10 +251,10 @@ fn foo() {
251 } 251 }
252 252
253 #[test] 253 #[test]
254 fn test_extract_assignment_chained_if() { 254 fn test_pull_assignment_up_chained_if() {
255 mark::check!(test_extract_assigment_chained_if); 255 mark::check!(test_pull_assignment_up_chained_if);
256 check_assist( 256 check_assist(
257 extract_assigment, 257 pull_assignment_up,
258 r#" 258 r#"
259fn foo() { 259fn foo() {
260 let mut a = 1; 260 let mut a = 1;
@@ -283,9 +283,9 @@ fn foo() {
283 } 283 }
284 284
285 #[test] 285 #[test]
286 fn test_extract_assigment_retains_stmts() { 286 fn test_pull_assignment_up_retains_stmts() {
287 check_assist( 287 check_assist(
288 extract_assigment, 288 pull_assignment_up,
289 r#" 289 r#"
290fn foo() { 290fn foo() {
291 let mut a = 1; 291 let mut a = 1;
@@ -314,9 +314,9 @@ fn foo() {
314 } 314 }
315 315
316 #[test] 316 #[test]
317 fn extract_assignment_let_stmt_not_applicable() { 317 fn pull_assignment_up_let_stmt_not_applicable() {
318 check_assist_not_applicable( 318 check_assist_not_applicable(
319 extract_assigment, 319 pull_assignment_up,
320 r#" 320 r#"
321fn foo() { 321fn foo() {
322 let mut a = 1; 322 let mut a = 1;
@@ -331,9 +331,9 @@ fn foo() {
331 } 331 }
332 332
333 #[test] 333 #[test]
334 fn extract_assignment_if_missing_assigment_not_applicable() { 334 fn pull_assignment_up_if_missing_assigment_not_applicable() {
335 check_assist_not_applicable( 335 check_assist_not_applicable(
336 extract_assigment, 336 pull_assignment_up,
337 r#" 337 r#"
338fn foo() { 338fn foo() {
339 let mut a = 1; 339 let mut a = 1;
@@ -346,9 +346,9 @@ fn foo() {
346 } 346 }
347 347
348 #[test] 348 #[test]
349 fn extract_assignment_match_missing_assigment_not_applicable() { 349 fn pull_assignment_up_match_missing_assigment_not_applicable() {
350 check_assist_not_applicable( 350 check_assist_not_applicable(
351 extract_assigment, 351 pull_assignment_up,
352 r#" 352 r#"
353fn foo() { 353fn foo() {
354 let mut a = 1; 354 let mut a = 1;
@@ -367,10 +367,10 @@ fn foo() {
367 } 367 }
368 368
369 #[test] 369 #[test]
370 fn test_extract_assignment_field_assignment() { 370 fn test_pull_assignment_up_field_assignment() {
371 mark::check!(test_extract_assignment_field_assignment); 371 mark::check!(test_pull_assignment_up_field_assignment);
372 check_assist( 372 check_assist(
373 extract_assigment, 373 pull_assignment_up,
374 r#" 374 r#"
375struct A(usize); 375struct A(usize);
376 376
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 212464f85..01baa65fe 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -116,7 +116,6 @@ mod handlers {
116 mod convert_integer_literal; 116 mod convert_integer_literal;
117 mod early_return; 117 mod early_return;
118 mod expand_glob_import; 118 mod expand_glob_import;
119 mod extract_assignment;
120 mod extract_module_to_file; 119 mod extract_module_to_file;
121 mod extract_struct_from_enum_variant; 120 mod extract_struct_from_enum_variant;
122 mod extract_variable; 121 mod extract_variable;
@@ -125,8 +124,8 @@ mod handlers {
125 mod flip_binexpr; 124 mod flip_binexpr;
126 mod flip_comma; 125 mod flip_comma;
127 mod flip_trait_bound; 126 mod flip_trait_bound;
128 mod generate_derive;
129 mod generate_default_from_enum_variant; 127 mod generate_default_from_enum_variant;
128 mod generate_derive;
130 mod generate_from_impl_for_enum; 129 mod generate_from_impl_for_enum;
131 mod generate_function; 130 mod generate_function;
132 mod generate_impl; 131 mod generate_impl;
@@ -139,6 +138,7 @@ mod handlers {
139 mod merge_match_arms; 138 mod merge_match_arms;
140 mod move_bounds; 139 mod move_bounds;
141 mod move_guard; 140 mod move_guard;
141 mod pull_assignment_up;
142 mod qualify_path; 142 mod qualify_path;
143 mod raw_string; 143 mod raw_string;
144 mod remove_dbg; 144 mod remove_dbg;
@@ -168,7 +168,6 @@ mod handlers {
168 convert_integer_literal::convert_integer_literal, 168 convert_integer_literal::convert_integer_literal,
169 early_return::convert_to_guarded_return, 169 early_return::convert_to_guarded_return,
170 expand_glob_import::expand_glob_import, 170 expand_glob_import::expand_glob_import,
171 extract_assignment::extract_assigment,
172 extract_module_to_file::extract_module_to_file, 171 extract_module_to_file::extract_module_to_file,
173 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 172 extract_struct_from_enum_variant::extract_struct_from_enum_variant,
174 extract_variable::extract_variable, 173 extract_variable::extract_variable,
@@ -177,8 +176,8 @@ mod handlers {
177 flip_binexpr::flip_binexpr, 176 flip_binexpr::flip_binexpr,
178 flip_comma::flip_comma, 177 flip_comma::flip_comma,
179 flip_trait_bound::flip_trait_bound, 178 flip_trait_bound::flip_trait_bound,
180 generate_derive::generate_derive,
181 generate_default_from_enum_variant::generate_default_from_enum_variant, 179 generate_default_from_enum_variant::generate_default_from_enum_variant,
180 generate_derive::generate_derive,
182 generate_from_impl_for_enum::generate_from_impl_for_enum, 181 generate_from_impl_for_enum::generate_from_impl_for_enum,
183 generate_function::generate_function, 182 generate_function::generate_function,
184 generate_impl::generate_impl, 183 generate_impl::generate_impl,
@@ -192,6 +191,7 @@ mod handlers {
192 move_bounds::move_bounds_to_where_clause, 191 move_bounds::move_bounds_to_where_clause,
193 move_guard::move_arm_cond_to_match_guard, 192 move_guard::move_arm_cond_to_match_guard,
194 move_guard::move_guard_to_arm_body, 193 move_guard::move_guard_to_arm_body,
194 pull_assignment_up::pull_assignment_up,
195 qualify_path::qualify_path, 195 qualify_path::qualify_path,
196 raw_string::add_hash, 196 raw_string::add_hash,
197 raw_string::make_usual_string, 197 raw_string::make_usual_string,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index b91a816e8..85e3c6742 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -238,35 +238,6 @@ fn qux(bar: Bar, baz: Baz) {}
238} 238}
239 239
240#[test] 240#[test]
241fn doctest_extract_assignment() {
242 check_doc_test(
243 "extract_assignment",
244 r#####"
245fn main() {
246 let mut foo = 6;
247
248 if true {
249 <|>foo = 5;
250 } else {
251 foo = 4;
252 }
253}
254"#####,
255 r#####"
256fn main() {
257 let mut foo = 6;
258
259 foo = if true {
260 5
261 } else {
262 4
263 };
264}
265"#####,
266 )
267}
268
269#[test]
270fn doctest_extract_module_to_file() { 241fn doctest_extract_module_to_file() {
271 check_doc_test( 242 check_doc_test(
272 "extract_module_to_file", 243 "extract_module_to_file",
@@ -767,6 +738,35 @@ fn handle(action: Action) {
767} 738}
768 739
769#[test] 740#[test]
741fn doctest_pull_assignment_up() {
742 check_doc_test(
743 "pull_assignment_up",
744 r#####"
745fn main() {
746 let mut foo = 6;
747
748 if true {
749 <|>foo = 5;
750 } else {
751 foo = 4;
752 }
753}
754"#####,
755 r#####"
756fn main() {
757 let mut foo = 6;
758
759 foo = if true {
760 5
761 } else {
762 4
763 };
764}
765"#####,
766 )
767}
768
769#[test]
770fn doctest_qualify_path() { 770fn doctest_qualify_path() {
771 check_doc_test( 771 check_doc_test(
772 "qualify_path", 772 "qualify_path",
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 62eccf475..a2255508e 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -5,9 +5,7 @@ use arrayvec::ArrayVec;
5use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 5use base_db::{CrateDisplayName, CrateId, Edition, FileId};
6use either::Either; 6use either::Either;
7use hir_def::{ 7use hir_def::{
8 adt::ReprKind, 8 adt::{ReprKind, StructKind, VariantData},
9 adt::StructKind,
10 adt::VariantData,
11 builtin_type::BuiltinType, 9 builtin_type::BuiltinType,
12 expr::{BindingAnnotation, LabelId, Pat, PatId}, 10 expr::{BindingAnnotation, LabelId, Pat, PatId},
13 import_map, 11 import_map,
@@ -31,7 +29,7 @@ use hir_expand::{
31}; 29};
32use hir_ty::{ 30use hir_ty::{
33 autoderef, 31 autoderef,
34 display::{HirDisplayError, HirFormatter}, 32 display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter},
35 method_resolution, 33 method_resolution,
36 traits::{FnTrait, Solution, SolutionVariables}, 34 traits::{FnTrait, Solution, SolutionVariables},
37 ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, 35 ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate,
@@ -1293,6 +1291,20 @@ impl TypeParam {
1293 } 1291 }
1294} 1292}
1295 1293
1294impl HirDisplay for TypeParam {
1295 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1296 write!(f, "{}", self.name(f.db))?;
1297 let bounds = f.db.generic_predicates_for_param(self.id);
1298 let substs = Substs::type_params(f.db, self.id.parent);
1299 let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
1300 if !(predicates.is_empty() || f.omit_verbose_types()) {
1301 write!(f, ": ")?;
1302 write_bounds_like_dyn_trait(&predicates, f)?;
1303 }
1304 Ok(())
1305 }
1306}
1307
1296#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 1308#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1297pub struct LifetimeParam { 1309pub struct LifetimeParam {
1298 pub(crate) id: LifetimeParamId, 1310 pub(crate) id: LifetimeParamId,
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 0e827a29e..a54225c18 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -595,7 +595,7 @@ impl HirDisplay for FnSig {
595 } 595 }
596} 596}
597 597
598fn write_bounds_like_dyn_trait( 598pub fn write_bounds_like_dyn_trait(
599 predicates: &[GenericPredicate], 599 predicates: &[GenericPredicate],
600 f: &mut HirFormatter, 600 f: &mut HirFormatter,
601) -> Result<(), HirDisplayError> { 601) -> Result<(), HirDisplayError> {
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs
index ea49d9f97..990f740b8 100644
--- a/crates/ide/src/display/short_label.rs
+++ b/crates/ide/src/display/short_label.rs
@@ -87,6 +87,17 @@ impl ShortLabel for ast::Variant {
87 } 87 }
88} 88}
89 89
90impl ShortLabel for ast::ConstParam {
91 fn short_label(&self) -> Option<String> {
92 let mut buf = "const ".to_owned();
93 buf.push_str(self.name()?.text().as_str());
94 if let Some(type_ref) = self.ty() {
95 format_to!(buf, ": {}", type_ref.syntax());
96 }
97 Some(buf)
98 }
99}
100
90fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> 101fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String>
91where 102where
92 T: NameOwner + VisibilityOwner, 103 T: NameOwner + VisibilityOwner,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 2737c900f..c0786eb51 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -70,7 +70,7 @@ impl HoverConfig {
70#[derive(Debug, Clone)] 70#[derive(Debug, Clone)]
71pub enum HoverAction { 71pub enum HoverAction {
72 Runnable(Runnable), 72 Runnable(Runnable),
73 Implementaion(FilePosition), 73 Implementation(FilePosition),
74 GoToType(Vec<HoverGotoTypeData>), 74 GoToType(Vec<HoverGotoTypeData>),
75} 75}
76 76
@@ -116,12 +116,13 @@ pub(crate) fn hover(
116 }; 116 };
117 if let Some(definition) = definition { 117 if let Some(definition) = definition {
118 if let Some(markup) = hover_for_definition(db, definition) { 118 if let Some(markup) = hover_for_definition(db, definition) {
119 let markup = markup.as_str();
119 let markup = if !markdown { 120 let markup = if !markdown {
120 remove_markdown(&markup.as_str()) 121 remove_markdown(markup)
121 } else if links_in_hover { 122 } else if links_in_hover {
122 rewrite_links(db, &markup.as_str(), &definition) 123 rewrite_links(db, markup, &definition)
123 } else { 124 } else {
124 remove_links(&markup.as_str()) 125 remove_links(markup)
125 }; 126 };
126 res.markup = Markup::from(markup); 127 res.markup = Markup::from(markup);
127 if let Some(action) = show_implementations_action(db, definition) { 128 if let Some(action) = show_implementations_action(db, definition) {
@@ -175,7 +176,7 @@ pub(crate) fn hover(
175 176
176fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 177fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
177 fn to_action(nav_target: NavigationTarget) -> HoverAction { 178 fn to_action(nav_target: NavigationTarget) -> HoverAction {
178 HoverAction::Implementaion(FilePosition { 179 HoverAction::Implementation(FilePosition {
179 file_id: nav_target.file_id, 180 file_id: nav_target.file_id,
180 offset: nav_target.focus_or_full_range().start(), 181 offset: nav_target.focus_or_full_range().start(),
181 }) 182 })
@@ -370,10 +371,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
370 } 371 }
371 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 372 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
372 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), 373 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
373 Definition::TypeParam(_) | Definition::ConstParam(_) => { 374 Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))),
374 // FIXME: Hover for generic param 375 Definition::ConstParam(it) => from_def_source(db, it, None),
375 None
376 }
377 }; 376 };
378 377
379 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> 378 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
@@ -1393,7 +1392,7 @@ fn bar() { fo<|>o(); }
1393 r"unsafe trait foo<|>() {}", 1392 r"unsafe trait foo<|>() {}",
1394 expect![[r#" 1393 expect![[r#"
1395 [ 1394 [
1396 Implementaion( 1395 Implementation(
1397 FilePosition { 1396 FilePosition {
1398 file_id: FileId( 1397 file_id: FileId(
1399 0, 1398 0,
@@ -2105,7 +2104,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2105 r#"trait foo<|>() {}"#, 2104 r#"trait foo<|>() {}"#,
2106 expect![[r#" 2105 expect![[r#"
2107 [ 2106 [
2108 Implementaion( 2107 Implementation(
2109 FilePosition { 2108 FilePosition {
2110 file_id: FileId( 2109 file_id: FileId(
2111 0, 2110 0,
@@ -2124,7 +2123,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2124 r"struct foo<|>() {}", 2123 r"struct foo<|>() {}",
2125 expect![[r#" 2124 expect![[r#"
2126 [ 2125 [
2127 Implementaion( 2126 Implementation(
2128 FilePosition { 2127 FilePosition {
2129 file_id: FileId( 2128 file_id: FileId(
2130 0, 2129 0,
@@ -2143,7 +2142,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2143 r#"union foo<|>() {}"#, 2142 r#"union foo<|>() {}"#,
2144 expect![[r#" 2143 expect![[r#"
2145 [ 2144 [
2146 Implementaion( 2145 Implementation(
2147 FilePosition { 2146 FilePosition {
2148 file_id: FileId( 2147 file_id: FileId(
2149 0, 2148 0,
@@ -2162,7 +2161,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2162 r"enum foo<|>() { A, B }", 2161 r"enum foo<|>() { A, B }",
2163 expect![[r#" 2162 expect![[r#"
2164 [ 2163 [
2165 Implementaion( 2164 Implementation(
2166 FilePosition { 2165 FilePosition {
2167 file_id: FileId( 2166 file_id: FileId(
2168 0, 2167 0,
@@ -3257,4 +3256,68 @@ fn foo() {
3257 "#]], 3256 "#]],
3258 ); 3257 );
3259 } 3258 }
3259
3260 #[test]
3261 fn hover_type_param() {
3262 check(
3263 r#"
3264struct Foo<T>(T);
3265trait Copy {}
3266trait Clone {}
3267trait Sized {}
3268impl<T: Copy + Clone> Foo<T<|>> where T: Sized {}
3269"#,
3270 expect![[r#"
3271 *T*
3272
3273 ```rust
3274 T: Copy + Clone + Sized
3275 ```
3276 "#]],
3277 );
3278 check(
3279 r#"
3280struct Foo<T>(T);
3281impl<T> Foo<T<|>> {}
3282"#,
3283 expect![[r#"
3284 *T*
3285
3286 ```rust
3287 T
3288 ```
3289 "#]],
3290 );
3291 // lifetimes aren't being substituted yet
3292 check(
3293 r#"
3294struct Foo<T>(T);
3295impl<T: 'static> Foo<T<|>> {}
3296"#,
3297 expect![[r#"
3298 *T*
3299
3300 ```rust
3301 T: {error}
3302 ```
3303 "#]],
3304 );
3305 }
3306
3307 #[test]
3308 fn hover_const_param() {
3309 check(
3310 r#"
3311struct Foo<const LEN: usize>;
3312impl<const LEN: usize> Foo<LEN<|>> {}
3313"#,
3314 expect![[r#"
3315 *LEN*
3316
3317 ```rust
3318 const LEN: usize
3319 ```
3320 "#]],
3321 );
3322 }
3260} 3323}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index dd486070b..c21ca044a 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1648,7 +1648,7 @@ fn prepare_hover_actions(
1648 actions 1648 actions
1649 .iter() 1649 .iter()
1650 .filter_map(|it| match it { 1650 .filter_map(|it| match it {
1651 HoverAction::Implementaion(position) => show_impl_command_link(snap, position), 1651 HoverAction::Implementation(position) => show_impl_command_link(snap, position),
1652 HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()), 1652 HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()),
1653 HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), 1653 HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
1654 }) 1654 })