Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/signature_help.rs')
-rw-r--r--crates/ide/src/signature_help.rs110
1 files changed, 68 insertions, 42 deletions
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs
index b6c9e2f636..516f64959c 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/signature_help.rs
@@ -4,15 +4,13 @@
use std::collections::BTreeSet;
use either::Either;
-use hir::{
- AssocItem, DescendPreference, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics,
- Trait,
-};
+use hir::{AssocItem, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait};
use ide_db::{
active_parameter::{callable_for_node, generic_def_for_node},
documentation::{Documentation, HasDocs},
FilePosition, FxIndexMap,
};
+use span::Edition;
use stdx::format_to;
use syntax::{
algo,
@@ -81,7 +79,9 @@ pub(crate) fn signature_help(
// if the cursor is sandwiched between two space tokens and the call is unclosed
// this prevents us from leaving the CallExpression
.and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
- let token = sema.descend_into_macros_single(DescendPreference::None, token);
+ let token = sema.descend_into_macros_single_exact(token);
+ let edition =
+ sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
for node in token.parent_ancestors() {
match_ast! {
@@ -91,49 +91,49 @@ pub(crate) fn signature_help(
if cursor_outside {
continue;
}
- return signature_help_for_call(&sema, arg_list, token);
+ return signature_help_for_call(&sema, arg_list, token, edition);
},
ast::GenericArgList(garg_list) => {
let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token);
if cursor_outside {
continue;
}
- return signature_help_for_generics(&sema, garg_list, token);
+ return signature_help_for_generics(&sema, garg_list, token, edition);
},
ast::RecordExpr(record) => {
let cursor_outside = record.record_expr_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);
if cursor_outside {
continue;
}
- return signature_help_for_record_lit(&sema, record, token);
+ return signature_help_for_record_lit(&sema, record, token, edition);
},
ast::RecordPat(record) => {
let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);
if cursor_outside {
continue;
}
- return signature_help_for_record_pat(&sema, record, token);
+ return signature_help_for_record_pat(&sema, record, token, edition);
},
ast::TupleStructPat(tuple_pat) => {
let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);
if cursor_outside {
continue;
}
- return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token);
+ return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token, edition);
},
ast::TuplePat(tuple_pat) => {
let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);
if cursor_outside {
continue;
}
- return signature_help_for_tuple_pat(&sema, tuple_pat, token);
+ return signature_help_for_tuple_pat(&sema, tuple_pat, token, edition);
},
ast::TupleExpr(tuple_expr) => {
let cursor_outside = tuple_expr.r_paren_token().as_ref() == Some(&token);
if cursor_outside {
continue;
}
- return signature_help_for_tuple_expr(&sema, tuple_expr, token);
+ return signature_help_for_tuple_expr(&sema, tuple_expr, token, edition);
},
_ => (),
}
@@ -157,6 +157,7 @@ fn signature_help_for_call(
sema: &Semantics<'_, RootDatabase>,
arg_list: ast::ArgList,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
// Find the calling expression and its NameRef
let mut nodes = arg_list.syntax().ancestors().skip(1);
@@ -181,7 +182,7 @@ fn signature_help_for_call(
match callable.kind() {
hir::CallableKind::Function(func) => {
res.doc = func.docs(db);
- format_to!(res.signature, "fn {}", func.name(db).display(db));
+ format_to!(res.signature, "fn {}", func.name(db).display(db, edition));
fn_params = Some(match callable.receiver_param(db) {
Some(_self) => func.params_without_self(db),
None => func.assoc_fn_params(db),
@@ -189,15 +190,15 @@ fn signature_help_for_call(
}
hir::CallableKind::TupleStruct(strukt) => {
res.doc = strukt.docs(db);
- format_to!(res.signature, "struct {}", strukt.name(db).display(db));
+ format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition));
}
hir::CallableKind::TupleEnumVariant(variant) => {
res.doc = variant.docs(db);
format_to!(
res.signature,
"enum {}::{}",
- variant.parent_enum(db).name(db).display(db),
- variant.name(db).display(db)
+ variant.parent_enum(db).name(db).display(db, edition),
+ variant.name(db).display(db, edition)
);
}
hir::CallableKind::Closure(closure) => {
@@ -210,7 +211,7 @@ fn signature_help_for_call(
Some(adt) => format_to!(
res.signature,
"<{} as {fn_trait}>::{}",
- adt.name(db).display(db),
+ adt.name(db).display(db, edition),
fn_trait.function_name()
),
None => format_to!(res.signature, "impl {fn_trait}"),
@@ -220,7 +221,7 @@ fn signature_help_for_call(
res.signature.push('(');
{
if let Some((self_param, _)) = callable.receiver_param(db) {
- format_to!(res.signature, "{}", self_param.display(db))
+ format_to!(res.signature, "{}", self_param.display(db, edition))
}
let mut buf = String::new();
for (idx, p) in callable.params().into_iter().enumerate() {
@@ -240,8 +241,10 @@ fn signature_help_for_call(
// This is overly conservative: we do not substitute known type vars
// (see FIXME in tests::impl_trait) and falling back on any unknowns.
match (p.ty().contains_unknown(), fn_params.as_deref()) {
- (true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)),
- _ => format_to!(buf, "{}", p.ty().display(db)),
+ (true, Some(fn_params)) => {
+ format_to!(buf, "{}", fn_params[idx].ty().display(db, edition))
+ }
+ _ => format_to!(buf, "{}", p.ty().display(db, edition)),
}
res.push_call_param(&buf);
}
@@ -250,7 +253,7 @@ fn signature_help_for_call(
let mut render = |ret_type: hir::Type| {
if !ret_type.is_unit() {
- format_to!(res.signature, " -> {}", ret_type.display(db));
+ format_to!(res.signature, " -> {}", ret_type.display(db, edition));
}
};
match callable.kind() {
@@ -270,6 +273,7 @@ fn signature_help_for_generics(
sema: &Semantics<'_, RootDatabase>,
arg_list: ast::GenericArgList,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) =
generic_def_for_node(sema, &arg_list, &token)?;
@@ -284,11 +288,11 @@ fn signature_help_for_generics(
match generics_def {
hir::GenericDef::Function(it) => {
res.doc = it.docs(db);
- format_to!(res.signature, "fn {}", it.name(db).display(db));
+ format_to!(res.signature, "fn {}", it.name(db).display(db, edition));
}
hir::GenericDef::Adt(hir::Adt::Enum(it)) => {
res.doc = it.docs(db);
- format_to!(res.signature, "enum {}", it.name(db).display(db));
+ format_to!(res.signature, "enum {}", it.name(db).display(db, edition));
if let Some(variant) = variant {
// In paths, generics of an enum can be specified *after* one of its variants.
// eg. `None::<u8>`
@@ -298,23 +302,23 @@ fn signature_help_for_generics(
}
hir::GenericDef::Adt(hir::Adt::Struct(it)) => {
res.doc = it.docs(db);
- format_to!(res.signature, "struct {}", it.name(db).display(db));
+ format_to!(res.signature, "struct {}", it.name(db).display(db, edition));
}
hir::GenericDef::Adt(hir::Adt::Union(it)) => {
res.doc = it.docs(db);
- format_to!(res.signature, "union {}", it.name(db).display(db));
+ format_to!(res.signature, "union {}", it.name(db).display(db, edition));
}
hir::GenericDef::Trait(it) => {
res.doc = it.docs(db);
- format_to!(res.signature, "trait {}", it.name(db).display(db));
+ format_to!(res.signature, "trait {}", it.name(db).display(db, edition));
}
hir::GenericDef::TraitAlias(it) => {
res.doc = it.docs(db);
- format_to!(res.signature, "trait {}", it.name(db).display(db));
+ format_to!(res.signature, "trait {}", it.name(db).display(db, edition));
}
hir::GenericDef::TypeAlias(it) => {
res.doc = it.docs(db);
- format_to!(res.signature, "type {}", it.name(db).display(db));
+ format_to!(res.signature, "type {}", it.name(db).display(db, edition));
}
// These don't have generic args that can be specified
hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None,
@@ -339,11 +343,11 @@ fn signature_help_for_generics(
}
buf.clear();
- format_to!(buf, "{}", param.display(db));
+ format_to!(buf, "{}", param.display(db, edition));
res.push_generic_param(&buf);
}
if let hir::GenericDef::Trait(tr) = generics_def {
- add_assoc_type_bindings(db, &mut res, tr, arg_list);
+ add_assoc_type_bindings(db, &mut res, tr, arg_list, edition);
}
res.signature.push('>');
@@ -355,6 +359,7 @@ fn add_assoc_type_bindings(
res: &mut SignatureHelp,
tr: Trait,
args: ast::GenericArgList,
+ edition: Edition,
) {
if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() {
// Assoc type bindings are only valid in type bound position.
@@ -378,7 +383,7 @@ fn add_assoc_type_bindings(
for item in tr.items_with_supertraits(db) {
if let AssocItem::TypeAlias(ty) = item {
- let name = ty.name(db).display_no_db().to_smolstr();
+ let name = ty.name(db).display_no_db(edition).to_smolstr();
if !present_bindings.contains(&*name) {
buf.clear();
format_to!(buf, "{} = …", name);
@@ -392,6 +397,7 @@ fn signature_help_for_record_lit(
sema: &Semantics<'_, RootDatabase>,
record: ast::RecordExpr,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
signature_help_for_record_(
sema,
@@ -403,6 +409,7 @@ fn signature_help_for_record_lit(
.filter_map(|field| sema.resolve_record_field(&field))
.map(|(field, _, ty)| (field, ty)),
token,
+ edition,
)
}
@@ -410,6 +417,7 @@ fn signature_help_for_record_pat(
sema: &Semantics<'_, RootDatabase>,
record: ast::RecordPat,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
signature_help_for_record_(
sema,
@@ -420,6 +428,7 @@ fn signature_help_for_record_pat(
.fields()
.filter_map(|field| sema.resolve_record_pat_field(&field)),
token,
+ edition,
)
}
@@ -427,6 +436,7 @@ fn signature_help_for_tuple_struct_pat(
sema: &Semantics<'_, RootDatabase>,
pat: ast::TupleStructPat,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
let path = pat.path()?;
let path_res = sema.resolve_path(&path)?;
@@ -445,8 +455,8 @@ fn signature_help_for_tuple_struct_pat(
format_to!(
res.signature,
"enum {}::{} (",
- en.name(db).display(db),
- variant.name(db).display(db)
+ en.name(db).display(db, edition),
+ variant.name(db).display(db, edition)
);
variant.fields(db)
} else {
@@ -459,7 +469,7 @@ fn signature_help_for_tuple_struct_pat(
match adt {
hir::Adt::Struct(it) => {
res.doc = it.docs(db);
- format_to!(res.signature, "struct {} (", it.name(db).display(db));
+ format_to!(res.signature, "struct {} (", it.name(db).display(db, edition));
it.fields(db)
}
_ => return None,
@@ -472,6 +482,7 @@ fn signature_help_for_tuple_struct_pat(
token,
pat.fields(),
fields.into_iter().map(|it| it.ty(db)),
+ edition,
))
}
@@ -479,6 +490,7 @@ fn signature_help_for_tuple_pat(
sema: &Semantics<'_, RootDatabase>,
pat: ast::TuplePat,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
let db = sema.db;
let field_pats = pat.fields();
@@ -498,6 +510,7 @@ fn signature_help_for_tuple_pat(
token,
field_pats,
fields.into_iter(),
+ edition,
))
}
@@ -505,6 +518,7 @@ fn signature_help_for_tuple_expr(
sema: &Semantics<'_, RootDatabase>,
expr: ast::TupleExpr,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
let active_parameter = Some(
expr.syntax()
@@ -526,7 +540,7 @@ fn signature_help_for_tuple_expr(
let fields = expr.original.tuple_fields(db);
let mut buf = String::new();
for ty in fields {
- format_to!(buf, "{}", ty.display_truncated(db, Some(20)));
+ format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition));
res.push_call_param(&buf);
buf.clear();
}
@@ -540,6 +554,7 @@ fn signature_help_for_record_(
path: &ast::Path,
fields2: impl Iterator<Item = (hir::Field, hir::Type)>,
token: SyntaxToken,
+ edition: Edition,
) -> Option<SignatureHelp> {
let active_parameter = field_list_children
.filter_map(NodeOrToken::into_token)
@@ -566,8 +581,8 @@ fn signature_help_for_record_(
format_to!(
res.signature,
"enum {}::{} {{ ",
- en.name(db).display(db),
- variant.name(db).display(db)
+ en.name(db).display(db, edition),
+ variant.name(db).display(db, edition)
);
} else {
let adt = match path_res {
@@ -580,12 +595,12 @@ fn signature_help_for_record_(
hir::Adt::Struct(it) => {
fields = it.fields(db);
res.doc = it.docs(db);
- format_to!(res.signature, "struct {} {{ ", it.name(db).display(db));
+ format_to!(res.signature, "struct {} {{ ", it.name(db).display(db, edition));
}
hir::Adt::Union(it) => {
fields = it.fields(db);
res.doc = it.docs(db);
- format_to!(res.signature, "union {} {{ ", it.name(db).display(db));
+ format_to!(res.signature, "union {} {{ ", it.name(db).display(db, edition));
}
_ => return None,
}
@@ -596,7 +611,12 @@ fn signature_help_for_record_(
let mut buf = String::new();
for (field, ty) in fields2 {
let name = field.name(db);
- format_to!(buf, "{}: {}", name.display(db), ty.display_truncated(db, Some(20)));
+ format_to!(
+ buf,
+ "{}: {}",
+ name.display(db, edition),
+ ty.display_truncated(db, Some(20), edition)
+ );
res.push_record_field(&buf);
buf.clear();
@@ -606,7 +626,12 @@ fn signature_help_for_record_(
}
for (name, field) in fields {
let Some(field) = field else { continue };
- format_to!(buf, "{}: {}", name.display(db), field.ty(db).display_truncated(db, Some(20)));
+ format_to!(
+ buf,
+ "{}: {}",
+ name.display(db, edition),
+ field.ty(db).display_truncated(db, Some(20), edition)
+ );
res.push_record_field(&buf);
buf.clear();
}
@@ -621,6 +646,7 @@ fn signature_help_for_tuple_pat_ish(
token: SyntaxToken,
mut field_pats: AstChildren<ast::Pat>,
fields: impl ExactSizeIterator<Item = hir::Type>,
+ edition: Edition,
) -> SignatureHelp {
let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_)));
let is_left_of_rest_pat =
@@ -647,7 +673,7 @@ fn signature_help_for_tuple_pat_ish(
let mut buf = String::new();
for ty in fields {
- format_to!(buf, "{}", ty.display_truncated(db, Some(20)));
+ format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition));
res.push_call_param(&buf);
buf.clear();
}