mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
feat: enhance signature help to display generic parameters for callables and default values for generic args
This commit is contained in:
parent
f766d1403e
commit
727d4b184d
@ -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,8 +864,8 @@ 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,8 +1328,8 @@ 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,8 +1773,8 @@ fn sup() {
|
|||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn test(&mut self, val: V)
|
fn test<V>(&mut self, val: V)
|
||||||
^^^^^^
|
^^^^^^
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1901,8 +1950,8 @@ 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…
x
Reference in New Issue
Block a user