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.rs | 89 |
1 files changed, 79 insertions, 10 deletions
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index 030790e470..06fdc641f8 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -4,11 +4,15 @@ use either::Either; use hir::{HasAttrs, HirDisplay, Semantics}; use ide_db::{ - active_parameter::{callable_for_token, generics_for_token}, + active_parameter::{callable_for_node, generics_for_token}, base_db::FilePosition, }; use stdx::format_to; -use syntax::{algo, AstNode, Direction, TextRange, TextSize}; +use syntax::{ + algo, + ast::{self, HasArgList}, + AstNode, Direction, SyntaxToken, TextRange, TextSize, +}; use crate::RootDatabase; @@ -65,8 +69,8 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?; let token = sema.descend_into_macros_single(token); - if let Some((callable, active_parameter)) = callable_for_token(&sema, token.clone()) { - return Some(signature_help_for_callable(db, callable, active_parameter)); + if let Some(help) = signature_help_for_call(&sema, &token) { + return Some(help); } if let Some((generic_def, active_parameter)) = generics_for_token(&sema, token.clone()) { @@ -76,14 +80,39 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio None } -fn signature_help_for_callable( - db: &RootDatabase, - callable: hir::Callable, - active_parameter: Option<usize>, -) -> SignatureHelp { +fn signature_help_for_call( + sema: &Semantics<RootDatabase>, + token: &SyntaxToken, +) -> Option<SignatureHelp> { + // Find the calling expression and its NameRef + let mut node = token.parent()?; + let calling_node = loop { + if let Some(callable) = ast::CallableExpr::cast(node.clone()) { + if callable + .arg_list() + .map_or(false, |it| it.syntax().text_range().contains(token.text_range().start())) + { + break callable; + } + } + + // Stop at multi-line expressions, since the signature of the outer call is not very + // helpful inside them. + if let Some(expr) = ast::Expr::cast(node.clone()) { + if expr.syntax().text().contains_char('\n') { + return None; + } + } + + node = node.parent()?; + }; + + let (callable, active_parameter) = callable_for_node(sema, &calling_node, token)?; + let mut res = SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter }; + let db = sema.db; match callable.kind() { hir::CallableKind::Function(func) => { res.doc = func.docs(db).map(|it| it.into()); @@ -134,7 +163,7 @@ fn signature_help_for_callable( } hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} } - res + Some(res) } fn signature_help_for_generics( @@ -787,6 +816,46 @@ fn main() { } #[test] + fn test_multiline_argument() { + check( + r#" +fn callee(a: u8, b: u8) {} +fn main() { + callee(match 0 { + 0 => 1,$0 + }) +}"#, + expect![[r#""#]], + ); + check( + r#" +fn callee(a: u8, b: u8) {} +fn main() { + callee(match 0 { + 0 => 1, + },$0) +}"#, + expect![[r#" + fn callee(a: u8, b: u8) + ----- ^^^^^ + "#]], + ); + check( + r#" +fn callee(a: u8, b: u8) {} +fn main() { + callee($0match 0 { + 0 => 1, + }) +}"#, + expect![[r#" + fn callee(a: u8, b: u8) + ^^^^^ ----- + "#]], + ); + } + + #[test] fn test_generics_simple() { check( r#" |