Skip to content

Commit d1554ee

Browse files
committed
feat: enhance signature help to display generic parameters for callables and default values for generic args
1 parent f766d14 commit d1554ee

File tree

1 file changed

+154
-13
lines changed

1 file changed

+154
-13
lines changed

crates/ide/src/signature_help.rs

+154-13
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ use std::collections::BTreeSet;
55

66
use either::Either;
77
use hir::{
8-
AssocItem, DisplayTarget, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait,
8+
AssocItem, DisplayTarget, GenericDef, GenericParam, HirDisplay, ModuleDef, PathResolution,
9+
Semantics, Trait,
910
};
1011
use ide_db::{
1112
FilePosition, FxIndexMap,
1213
active_parameter::{callable_for_arg_list, generic_def_for_node},
1314
documentation::{Documentation, HasDocs},
1415
};
16+
use itertools::Itertools;
1517
use span::Edition;
1618
use stdx::format_to;
1719
use syntax::{
@@ -175,6 +177,20 @@ fn signature_help_for_call(
175177
hir::CallableKind::Function(func) => {
176178
res.doc = func.docs(db);
177179
format_to!(res.signature, "fn {}", func.name(db).display(db, edition));
180+
181+
let generic_params = GenericDef::Function(func)
182+
.params(db)
183+
.iter()
184+
.filter(|param| match param {
185+
GenericParam::TypeParam(type_param) => !type_param.is_implicit(db),
186+
GenericParam::ConstParam(_) | GenericParam::LifetimeParam(_) => true,
187+
})
188+
.map(|param| param.display(db, display_target))
189+
.join(", ");
190+
if !generic_params.is_empty() {
191+
format_to!(res.signature, "<{}>", generic_params);
192+
}
193+
178194
fn_params = Some(match callable.receiver_param(db) {
179195
Some(_self) => func.params_without_self(db),
180196
None => func.assoc_fn_params(db),
@@ -183,15 +199,34 @@ fn signature_help_for_call(
183199
hir::CallableKind::TupleStruct(strukt) => {
184200
res.doc = strukt.docs(db);
185201
format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition));
202+
203+
let generic_params = GenericDef::Adt(strukt.into())
204+
.params(db)
205+
.iter()
206+
.map(|param| param.display(db, display_target))
207+
.join(", ");
208+
if !generic_params.is_empty() {
209+
format_to!(res.signature, "<{}>", generic_params);
210+
}
186211
}
187212
hir::CallableKind::TupleEnumVariant(variant) => {
188213
res.doc = variant.docs(db);
189214
format_to!(
190215
res.signature,
191-
"enum {}::{}",
216+
"enum {}",
192217
variant.parent_enum(db).name(db).display(db, edition),
193-
variant.name(db).display(db, edition)
194218
);
219+
220+
let generic_params = GenericDef::Adt(variant.parent_enum(db).into())
221+
.params(db)
222+
.iter()
223+
.map(|param| param.display(db, display_target))
224+
.join(", ");
225+
if !generic_params.is_empty() {
226+
format_to!(res.signature, "<{}>", generic_params);
227+
}
228+
229+
format_to!(res.signature, "::{}", variant.name(db).display(db, edition))
195230
}
196231
hir::CallableKind::Closure(closure) => {
197232
let fn_trait = closure.fn_trait(db);
@@ -339,6 +374,20 @@ fn signature_help_for_generics(
339374

340375
buf.clear();
341376
format_to!(buf, "{}", param.display(db, display_target));
377+
match param {
378+
GenericParam::TypeParam(param) => {
379+
if let Some(ty) = param.default(db) {
380+
format_to!(buf, " = {}", ty.display(db, display_target));
381+
}
382+
}
383+
GenericParam::ConstParam(param) => {
384+
if let Some(expr) = param.default(db, display_target).and_then(|konst| konst.expr())
385+
{
386+
format_to!(buf, " = {}", expr);
387+
}
388+
}
389+
_ => {}
390+
}
342391
res.push_generic_param(&buf);
343392
}
344393
if let hir::GenericDef::Trait(tr) = generics_def {
@@ -815,8 +864,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
815864
fn bar() { foo($03, ); }
816865
"#,
817866
expect![[r#"
818-
fn foo(x: i32, y: U) -> u32
819-
^^^^^^ ----
867+
fn foo<T, U>(x: i32, y: U) -> u32
868+
^^^^^^ ----
820869
"#]],
821870
);
822871
}
@@ -829,7 +878,7 @@ fn foo<T>() -> T where T: Copy + Display {}
829878
fn bar() { foo($0); }
830879
"#,
831880
expect![[r#"
832-
fn foo() -> T
881+
fn foo<T>() -> T
833882
"#]],
834883
);
835884
}
@@ -1279,8 +1328,8 @@ fn main() {
12791328
}
12801329
"#,
12811330
expect![[r#"
1282-
struct S({unknown})
1283-
^^^^^^^^^
1331+
struct S<T>({unknown})
1332+
^^^^^^^^^
12841333
"#]],
12851334
);
12861335
}
@@ -1375,7 +1424,7 @@ id! {
13751424
fn test() { S.foo($0); }
13761425
"#,
13771426
expect![[r#"
1378-
fn foo(&'a mut self)
1427+
fn foo<'a>(&'a mut self)
13791428
"#]],
13801429
);
13811430
}
@@ -1724,8 +1773,8 @@ fn sup() {
17241773
}
17251774
"#,
17261775
expect![[r#"
1727-
fn test(&mut self, val: V)
1728-
^^^^^^
1776+
fn test<V>(&mut self, val: V)
1777+
^^^^^^
17291778
"#]],
17301779
);
17311780
}
@@ -1901,8 +1950,8 @@ fn f() {
19011950
}
19021951
"#,
19031952
expect![[r#"
1904-
fn foo(x: Wrap<impl Trait<U>>)
1905-
^^^^^^^^^^^^^^^^^^^^^^
1953+
fn foo<U>(x: Wrap<impl Trait<U>>)
1954+
^^^^^^^^^^^^^^^^^^^^^^
19061955
"#]],
19071956
);
19081957
}
@@ -2394,4 +2443,96 @@ fn main() {
23942443
"#]],
23952444
);
23962445
}
2446+
2447+
#[test]
2448+
fn test_tuple_generic_param() {
2449+
check(
2450+
r#"
2451+
struct S<T>(T);
2452+
2453+
fn main() {
2454+
let s: S<$0
2455+
}
2456+
"#,
2457+
expect![[r#"
2458+
struct S<T>
2459+
^
2460+
"#]],
2461+
);
2462+
}
2463+
2464+
#[test]
2465+
fn test_enum_generic_param() {
2466+
check(
2467+
r#"
2468+
enum Option<T> {
2469+
Some(T),
2470+
None,
2471+
}
2472+
2473+
fn main() {
2474+
let opt: Option<$0
2475+
}
2476+
"#,
2477+
expect![[r#"
2478+
enum Option<T>
2479+
^
2480+
"#]],
2481+
);
2482+
}
2483+
2484+
#[test]
2485+
fn test_enum_variant_generic_param() {
2486+
check(
2487+
r#"
2488+
enum Option<T> {
2489+
Some(T),
2490+
None,
2491+
}
2492+
2493+
fn main() {
2494+
let opt = Option::Some($0);
2495+
}
2496+
"#,
2497+
expect![[r#"
2498+
enum Option<T>::Some({unknown})
2499+
^^^^^^^^^
2500+
"#]],
2501+
);
2502+
}
2503+
2504+
#[test]
2505+
fn test_generic_arg_with_default() {
2506+
check(
2507+
r#"
2508+
struct S<T = u8> {
2509+
field: T,
2510+
}
2511+
2512+
fn main() {
2513+
let s: S<$0
23972514
}
2515+
"#,
2516+
expect![[r#"
2517+
struct S<T = u8>
2518+
^^^^^^
2519+
"#]],
2520+
);
2521+
2522+
check(
2523+
r#"
2524+
struct S<const C: u8 = 5> {
2525+
field: C,
2526+
}
2527+
2528+
fn main() {
2529+
let s: S<$0
2530+
}
2531+
"#,
2532+
expect![[r#"
2533+
struct S<const C: u8 = 5>
2534+
^^^^^^^^^^^^^^^
2535+
"#]],
2536+
);
2537+
}
2538+
}

0 commit comments

Comments
 (0)