mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 03:54:42 +00:00 
			
		
		
		
	Merge pull request #19596 from roife/sig-help-info
feat: enhance signature help to display generic parameters for callables and default values for generic args
This commit is contained in:
		
						commit
						d5a3d14cac
					
				
					 1 changed files with 154 additions and 13 deletions
				
			
		|  | @ -5,13 +5,15 @@ use std::collections::BTreeSet; | ||||||
| 
 | 
 | ||||||
| use either::Either; | use either::Either; | ||||||
| use hir::{ | use hir::{ | ||||||
|     AssocItem, DisplayTarget, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait, |     AssocItem, DisplayTarget, GenericDef, GenericParam, HirDisplay, ModuleDef, PathResolution, | ||||||
|  |     Semantics, Trait, | ||||||
| }; | }; | ||||||
| use ide_db::{ | use ide_db::{ | ||||||
|     FilePosition, FxIndexMap, |     FilePosition, FxIndexMap, | ||||||
|     active_parameter::{callable_for_arg_list, generic_def_for_node}, |     active_parameter::{callable_for_arg_list, generic_def_for_node}, | ||||||
|     documentation::{Documentation, HasDocs}, |     documentation::{Documentation, HasDocs}, | ||||||
| }; | }; | ||||||
|  | use itertools::Itertools; | ||||||
| use span::Edition; | use span::Edition; | ||||||
| use stdx::format_to; | use stdx::format_to; | ||||||
| use syntax::{ | use syntax::{ | ||||||
|  | @ -175,6 +177,20 @@ fn signature_help_for_call( | ||||||
|         hir::CallableKind::Function(func) => { |         hir::CallableKind::Function(func) => { | ||||||
|             res.doc = func.docs(db); |             res.doc = func.docs(db); | ||||||
|             format_to!(res.signature, "fn {}", func.name(db).display(db, edition)); |             format_to!(res.signature, "fn {}", func.name(db).display(db, edition)); | ||||||
|  | 
 | ||||||
|  |             let generic_params = GenericDef::Function(func) | ||||||
|  |                 .params(db) | ||||||
|  |                 .iter() | ||||||
|  |                 .filter(|param| match param { | ||||||
|  |                     GenericParam::TypeParam(type_param) => !type_param.is_implicit(db), | ||||||
|  |                     GenericParam::ConstParam(_) | GenericParam::LifetimeParam(_) => true, | ||||||
|  |                 }) | ||||||
|  |                 .map(|param| param.display(db, display_target)) | ||||||
|  |                 .join(", "); | ||||||
|  |             if !generic_params.is_empty() { | ||||||
|  |                 format_to!(res.signature, "<{}>", generic_params); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             fn_params = Some(match callable.receiver_param(db) { |             fn_params = Some(match callable.receiver_param(db) { | ||||||
|                 Some(_self) => func.params_without_self(db), |                 Some(_self) => func.params_without_self(db), | ||||||
|                 None => func.assoc_fn_params(db), |                 None => func.assoc_fn_params(db), | ||||||
|  | @ -183,15 +199,34 @@ fn signature_help_for_call( | ||||||
|         hir::CallableKind::TupleStruct(strukt) => { |         hir::CallableKind::TupleStruct(strukt) => { | ||||||
|             res.doc = strukt.docs(db); |             res.doc = strukt.docs(db); | ||||||
|             format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition)); |             format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition)); | ||||||
|  | 
 | ||||||
|  |             let generic_params = GenericDef::Adt(strukt.into()) | ||||||
|  |                 .params(db) | ||||||
|  |                 .iter() | ||||||
|  |                 .map(|param| param.display(db, display_target)) | ||||||
|  |                 .join(", "); | ||||||
|  |             if !generic_params.is_empty() { | ||||||
|  |                 format_to!(res.signature, "<{}>", generic_params); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         hir::CallableKind::TupleEnumVariant(variant) => { |         hir::CallableKind::TupleEnumVariant(variant) => { | ||||||
|             res.doc = variant.docs(db); |             res.doc = variant.docs(db); | ||||||
|             format_to!( |             format_to!( | ||||||
|                 res.signature, |                 res.signature, | ||||||
|                 "enum {}::{}", |                 "enum {}", | ||||||
|                 variant.parent_enum(db).name(db).display(db, edition), |                 variant.parent_enum(db).name(db).display(db, edition), | ||||||
|                 variant.name(db).display(db, edition) |  | ||||||
|             ); |             ); | ||||||
|  | 
 | ||||||
|  |             let generic_params = GenericDef::Adt(variant.parent_enum(db).into()) | ||||||
|  |                 .params(db) | ||||||
|  |                 .iter() | ||||||
|  |                 .map(|param| param.display(db, display_target)) | ||||||
|  |                 .join(", "); | ||||||
|  |             if !generic_params.is_empty() { | ||||||
|  |                 format_to!(res.signature, "<{}>", generic_params); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             format_to!(res.signature, "::{}", variant.name(db).display(db, edition)) | ||||||
|         } |         } | ||||||
|         hir::CallableKind::Closure(closure) => { |         hir::CallableKind::Closure(closure) => { | ||||||
|             let fn_trait = closure.fn_trait(db); |             let fn_trait = closure.fn_trait(db); | ||||||
|  | @ -339,6 +374,20 @@ fn signature_help_for_generics( | ||||||
| 
 | 
 | ||||||
|         buf.clear(); |         buf.clear(); | ||||||
|         format_to!(buf, "{}", param.display(db, display_target)); |         format_to!(buf, "{}", param.display(db, display_target)); | ||||||
|  |         match param { | ||||||
|  |             GenericParam::TypeParam(param) => { | ||||||
|  |                 if let Some(ty) = param.default(db) { | ||||||
|  |                     format_to!(buf, " = {}", ty.display(db, display_target)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             GenericParam::ConstParam(param) => { | ||||||
|  |                 if let Some(expr) = param.default(db, display_target).and_then(|konst| konst.expr()) | ||||||
|  |                 { | ||||||
|  |                     format_to!(buf, " = {}", expr); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             _ => {} | ||||||
|  |         } | ||||||
|         res.push_generic_param(&buf); |         res.push_generic_param(&buf); | ||||||
|     } |     } | ||||||
|     if let hir::GenericDef::Trait(tr) = generics_def { |     if let hir::GenericDef::Trait(tr) = generics_def { | ||||||
|  | @ -815,7 +864,7 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | ||||||
| fn bar() { foo($03, ); } | fn bar() { foo($03, ); } | ||||||
| "#,
 | "#,
 | ||||||
|             expect![[r#" |             expect![[r#" | ||||||
|                 fn foo(x: i32, y: U) -> u32 |                 fn foo<T, U>(x: i32, y: U) -> u32 | ||||||
|                              ^^^^^^  ---- |                              ^^^^^^  ---- | ||||||
|             "#]],
 |             "#]],
 | ||||||
|         ); |         ); | ||||||
|  | @ -829,7 +878,7 @@ fn foo<T>() -> T where T: Copy + Display {} | ||||||
| fn bar() { foo($0); } | fn bar() { foo($0); } | ||||||
| "#,
 | "#,
 | ||||||
|             expect![[r#" |             expect![[r#" | ||||||
|                 fn foo() -> T |                 fn foo<T>() -> T | ||||||
|             "#]],
 |             "#]],
 | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | @ -1279,7 +1328,7 @@ fn main() { | ||||||
| } | } | ||||||
| "#,
 | "#,
 | ||||||
|             expect![[r#" |             expect![[r#" | ||||||
|                 struct S({unknown}) |                 struct S<T>({unknown}) | ||||||
|                             ^^^^^^^^^ |                             ^^^^^^^^^ | ||||||
|             "#]],
 |             "#]],
 | ||||||
|         ); |         ); | ||||||
|  | @ -1375,7 +1424,7 @@ id! { | ||||||
| fn test() { S.foo($0); } | fn test() { S.foo($0); } | ||||||
| "#,
 | "#,
 | ||||||
|             expect![[r#" |             expect![[r#" | ||||||
|                 fn foo(&'a mut self) |                 fn foo<'a>(&'a mut self) | ||||||
|             "#]],
 |             "#]],
 | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | @ -1724,7 +1773,7 @@ fn sup() { | ||||||
| } | } | ||||||
| "#,
 | "#,
 | ||||||
|             expect![[r#" |             expect![[r#" | ||||||
|                 fn test(&mut self, val: V) |                 fn test<V>(&mut self, val: V) | ||||||
|                                       ^^^^^^ |                                       ^^^^^^ | ||||||
|             "#]],
 |             "#]],
 | ||||||
|         ); |         ); | ||||||
|  | @ -1901,7 +1950,7 @@ fn f() { | ||||||
| } | } | ||||||
| "#,
 | "#,
 | ||||||
|             expect![[r#" |             expect![[r#" | ||||||
|                 fn foo(x: Wrap<impl Trait<U>>) |                 fn foo<U>(x: Wrap<impl Trait<U>>) | ||||||
|                           ^^^^^^^^^^^^^^^^^^^^^^ |                           ^^^^^^^^^^^^^^^^^^^^^^ | ||||||
|             "#]],
 |             "#]],
 | ||||||
|         ); |         ); | ||||||
|  | @ -2394,4 +2443,96 @@ fn main() { | ||||||
|             "#]],
 |             "#]],
 | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn test_tuple_generic_param() { | ||||||
|  |         check( | ||||||
|  |             r#" | ||||||
|  | struct S<T>(T); | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let s: S<$0 | ||||||
|  | } | ||||||
|  |             "#,
 | ||||||
|  |             expect![[r#" | ||||||
|  |                 struct S<T> | ||||||
|  |                          ^ | ||||||
|  |             "#]],
 | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn test_enum_generic_param() { | ||||||
|  |         check( | ||||||
|  |             r#" | ||||||
|  | enum Option<T> { | ||||||
|  |     Some(T), | ||||||
|  |     None, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let opt: Option<$0 | ||||||
|  | } | ||||||
|  |             "#,
 | ||||||
|  |             expect![[r#" | ||||||
|  |                 enum Option<T> | ||||||
|  |                             ^ | ||||||
|  |             "#]],
 | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn test_enum_variant_generic_param() { | ||||||
|  |         check( | ||||||
|  |             r#" | ||||||
|  | enum Option<T> { | ||||||
|  |     Some(T), | ||||||
|  |     None, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let opt = Option::Some($0); | ||||||
|  | } | ||||||
|  |             "#,
 | ||||||
|  |             expect![[r#" | ||||||
|  |                 enum Option<T>::Some({unknown}) | ||||||
|  |                                      ^^^^^^^^^ | ||||||
|  |             "#]],
 | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn test_generic_arg_with_default() { | ||||||
|  |         check( | ||||||
|  |             r#" | ||||||
|  | struct S<T = u8> { | ||||||
|  |     field: T, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let s: S<$0 | ||||||
|  | } | ||||||
|  |             "#,
 | ||||||
|  |             expect![[r#" | ||||||
|  |                 struct S<T = u8> | ||||||
|  |                          ^^^^^^ | ||||||
|  |             "#]],
 | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         check( | ||||||
|  |             r#" | ||||||
|  | struct S<const C: u8 = 5> { | ||||||
|  |     field: C, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let s: S<$0 | ||||||
|  | } | ||||||
|  |             "#,
 | ||||||
|  |             expect![[r#" | ||||||
|  |                 struct S<const C: u8 = 5> | ||||||
|  |                          ^^^^^^^^^^^^^^^ | ||||||
|  |             "#]],
 | ||||||
|  |         ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth