Skip to content

Commit 4e07864

Browse files
author
Jonas Schievink
committed
signature help: skip lifetimes when non-lifetime arguments are present
1 parent b7cc9a7 commit 4e07864

File tree

2 files changed

+84
-64
lines changed

2 files changed

+84
-64
lines changed

crates/ide/src/signature_help.rs

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22
//! a call or use-site.
33
44
use either::Either;
5-
use hir::{HasAttrs, HirDisplay, Semantics};
6-
use ide_db::{
7-
active_parameter::{callable_for_node, generics_for_token},
8-
base_db::FilePosition,
9-
};
5+
use hir::{GenericParam, HasAttrs, HirDisplay, Semantics};
6+
use ide_db::{active_parameter::callable_for_node, base_db::FilePosition};
107
use stdx::format_to;
118
use syntax::{
129
algo,
@@ -73,8 +70,8 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio
7370
return Some(help);
7471
}
7572

76-
if let Some((generic_def, active_parameter)) = generics_for_token(&sema, token.clone()) {
77-
return signature_help_for_generics(db, generic_def, active_parameter);
73+
if let Some(help) = signature_help_for_generics(&sema, &token) {
74+
return Some(help);
7875
}
7976

8077
None
@@ -167,17 +164,69 @@ fn signature_help_for_call(
167164
}
168165

169166
fn signature_help_for_generics(
170-
db: &RootDatabase,
171-
mut generics_def: hir::GenericDef,
172-
active_parameter: usize,
167+
sema: &Semantics<RootDatabase>,
168+
token: &SyntaxToken,
173169
) -> Option<SignatureHelp> {
170+
let parent = token.parent()?;
171+
let arg_list = parent
172+
.ancestors()
173+
.filter_map(ast::GenericArgList::cast)
174+
.find(|list| list.syntax().text_range().contains(token.text_range().start()))?;
175+
176+
let mut active_parameter = arg_list
177+
.generic_args()
178+
.take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
179+
.count();
180+
181+
let first_arg_is_non_lifetime = arg_list
182+
.generic_args()
183+
.next()
184+
.map_or(false, |arg| !matches!(arg, ast::GenericArg::LifetimeArg(_)));
185+
186+
let mut generics_def = if let Some(path) =
187+
arg_list.syntax().ancestors().find_map(ast::Path::cast)
188+
{
189+
let res = sema.resolve_path(&path)?;
190+
let generic_def: hir::GenericDef = match res {
191+
hir::PathResolution::Def(hir::ModuleDef::Adt(it)) => it.into(),
192+
hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(),
193+
hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(),
194+
hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(),
195+
hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => it.into(),
196+
hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))
197+
| hir::PathResolution::Def(hir::ModuleDef::Const(_))
198+
| hir::PathResolution::Def(hir::ModuleDef::Macro(_))
199+
| hir::PathResolution::Def(hir::ModuleDef::Module(_))
200+
| hir::PathResolution::Def(hir::ModuleDef::Static(_)) => return None,
201+
hir::PathResolution::AssocItem(hir::AssocItem::Function(it)) => it.into(),
202+
hir::PathResolution::AssocItem(hir::AssocItem::TypeAlias(it)) => it.into(),
203+
hir::PathResolution::AssocItem(hir::AssocItem::Const(_)) => return None,
204+
hir::PathResolution::BuiltinAttr(_)
205+
| hir::PathResolution::ToolModule(_)
206+
| hir::PathResolution::Local(_)
207+
| hir::PathResolution::TypeParam(_)
208+
| hir::PathResolution::ConstParam(_)
209+
| hir::PathResolution::SelfType(_) => return None,
210+
};
211+
212+
generic_def
213+
} else if let Some(method_call) = arg_list.syntax().parent().and_then(ast::MethodCallExpr::cast)
214+
{
215+
// recv.method::<$0>()
216+
let method = sema.resolve_method_call(&method_call)?;
217+
method.into()
218+
} else {
219+
return None;
220+
};
221+
174222
let mut res = SignatureHelp {
175223
doc: None,
176224
signature: String::new(),
177225
parameters: vec![],
178-
active_parameter: Some(active_parameter),
226+
active_parameter: None,
179227
};
180228

229+
let db = sema.db;
181230
match generics_def {
182231
hir::GenericDef::Function(it) => {
183232
res.doc = it.docs(db).map(|it| it.into());
@@ -216,8 +265,16 @@ fn signature_help_for_generics(
216265
hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None,
217266
}
218267

268+
let params = generics_def.params(sema.db);
269+
let num_lifetime_params =
270+
params.iter().take_while(|param| matches!(param, GenericParam::LifetimeParam(_))).count();
271+
if first_arg_is_non_lifetime {
272+
// Lifetime parameters were omitted.
273+
active_parameter += num_lifetime_params;
274+
}
275+
res.active_parameter = Some(active_parameter);
276+
219277
res.signature.push('<');
220-
let params = generics_def.params(db);
221278
let mut buf = String::new();
222279
for param in params {
223280
if let hir::GenericParam::TypeParam(ty) = param {
@@ -976,14 +1033,27 @@ fn f() {
9761033
fn test_generic_kinds() {
9771034
check(
9781035
r#"
979-
fn callee<'a, const A: (), T, const C: u8>() {}
1036+
fn callee<'a, const A: u8, T, const C: u8>() {}
9801037
9811038
fn f() {
9821039
callee::<'static, $0
9831040
}
9841041
"#,
9851042
expect![[r#"
986-
fn callee<'a, const A: (), T, const C: u8>
1043+
fn callee<'a, const A: u8, T, const C: u8>
1044+
-- ^^^^^^^^^^^ - -----------
1045+
"#]],
1046+
);
1047+
check(
1048+
r#"
1049+
fn callee<'a, const A: u8, T, const C: u8>() {}
1050+
1051+
fn f() {
1052+
callee::<NON_LIFETIME$0
1053+
}
1054+
"#,
1055+
expect![[r#"
1056+
fn callee<'a, const A: u8, T, const C: u8>
9871057
-- ^^^^^^^^^^^ - -----------
9881058
"#]],
9891059
);

crates/ide_db/src/active_parameter.rs

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -76,53 +76,3 @@ pub fn callable_for_node(
7676
};
7777
Some((callable, active_param))
7878
}
79-
80-
pub fn generics_for_token(
81-
sema: &Semantics<RootDatabase>,
82-
token: SyntaxToken,
83-
) -> Option<(hir::GenericDef, usize)> {
84-
let parent = token.parent()?;
85-
let arg_list = parent
86-
.ancestors()
87-
.filter_map(ast::GenericArgList::cast)
88-
.find(|list| list.syntax().text_range().contains(token.text_range().start()))?;
89-
90-
let active_param = arg_list
91-
.generic_args()
92-
.take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
93-
.count();
94-
95-
if let Some(path) = arg_list.syntax().ancestors().find_map(ast::Path::cast) {
96-
let res = sema.resolve_path(&path)?;
97-
let generic_def: hir::GenericDef = match res {
98-
hir::PathResolution::Def(hir::ModuleDef::Adt(it)) => it.into(),
99-
hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(),
100-
hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(),
101-
hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(),
102-
hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => it.into(),
103-
hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))
104-
| hir::PathResolution::Def(hir::ModuleDef::Const(_))
105-
| hir::PathResolution::Def(hir::ModuleDef::Macro(_))
106-
| hir::PathResolution::Def(hir::ModuleDef::Module(_))
107-
| hir::PathResolution::Def(hir::ModuleDef::Static(_)) => return None,
108-
hir::PathResolution::AssocItem(hir::AssocItem::Function(it)) => it.into(),
109-
hir::PathResolution::AssocItem(hir::AssocItem::TypeAlias(it)) => it.into(),
110-
hir::PathResolution::AssocItem(hir::AssocItem::Const(_)) => return None,
111-
hir::PathResolution::BuiltinAttr(_)
112-
| hir::PathResolution::ToolModule(_)
113-
| hir::PathResolution::Local(_)
114-
| hir::PathResolution::TypeParam(_)
115-
| hir::PathResolution::ConstParam(_)
116-
| hir::PathResolution::SelfType(_) => return None,
117-
};
118-
119-
Some((generic_def, active_param))
120-
} else if let Some(method_call) = arg_list.syntax().parent().and_then(ast::MethodCallExpr::cast)
121-
{
122-
// recv.method::<$0>()
123-
let method = sema.resolve_method_call(&method_call)?;
124-
Some((method.into(), active_param))
125-
} else {
126-
None
127-
}
128-
}

0 commit comments

Comments
 (0)