mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
parent
c9cefb9916
commit
4bb5df0ce5
2 changed files with 88 additions and 11 deletions
|
@ -4,11 +4,15 @@
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{HasAttrs, HirDisplay, Semantics};
|
use hir::{HasAttrs, HirDisplay, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
active_parameter::{callable_for_token, generics_for_token},
|
active_parameter::{callable_for_node, generics_for_token},
|
||||||
base_db::FilePosition,
|
base_db::FilePosition,
|
||||||
};
|
};
|
||||||
use stdx::format_to;
|
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;
|
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))?;
|
.and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
|
||||||
let token = sema.descend_into_macros_single(token);
|
let token = sema.descend_into_macros_single(token);
|
||||||
|
|
||||||
if let Some((callable, active_parameter)) = callable_for_token(&sema, token.clone()) {
|
if let Some(help) = signature_help_for_call(&sema, &token) {
|
||||||
return Some(signature_help_for_callable(db, callable, active_parameter));
|
return Some(help);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((generic_def, active_parameter)) = generics_for_token(&sema, token.clone()) {
|
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
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature_help_for_callable(
|
fn signature_help_for_call(
|
||||||
db: &RootDatabase,
|
sema: &Semantics<RootDatabase>,
|
||||||
callable: hir::Callable,
|
token: &SyntaxToken,
|
||||||
active_parameter: Option<usize>,
|
) -> Option<SignatureHelp> {
|
||||||
) -> 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 =
|
let mut res =
|
||||||
SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };
|
SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };
|
||||||
|
|
||||||
|
let db = sema.db;
|
||||||
match callable.kind() {
|
match callable.kind() {
|
||||||
hir::CallableKind::Function(func) => {
|
hir::CallableKind::Function(func) => {
|
||||||
res.doc = func.docs(db).map(|it| it.into());
|
res.doc = func.docs(db).map(|it| it.into());
|
||||||
|
@ -134,7 +163,7 @@ fn signature_help_for_callable(
|
||||||
}
|
}
|
||||||
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
||||||
}
|
}
|
||||||
res
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature_help_for_generics(
|
fn signature_help_for_generics(
|
||||||
|
@ -786,6 +815,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]
|
#[test]
|
||||||
fn test_generics_simple() {
|
fn test_generics_simple() {
|
||||||
check(
|
check(
|
||||||
|
|
|
@ -43,13 +43,21 @@ pub fn callable_for_token(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
token: SyntaxToken,
|
token: SyntaxToken,
|
||||||
) -> Option<(hir::Callable, Option<usize>)> {
|
) -> Option<(hir::Callable, Option<usize>)> {
|
||||||
// Find the calling expression and it's NameRef
|
// Find the calling expression and its NameRef
|
||||||
let parent = token.parent()?;
|
let parent = token.parent()?;
|
||||||
let calling_node = parent.ancestors().filter_map(ast::CallableExpr::cast).find(|it| {
|
let calling_node = parent.ancestors().filter_map(ast::CallableExpr::cast).find(|it| {
|
||||||
it.arg_list()
|
it.arg_list()
|
||||||
.map_or(false, |it| it.syntax().text_range().contains(token.text_range().start()))
|
.map_or(false, |it| it.syntax().text_range().contains(token.text_range().start()))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
callable_for_node(sema, &calling_node, &token)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn callable_for_node(
|
||||||
|
sema: &Semantics<RootDatabase>,
|
||||||
|
calling_node: &ast::CallableExpr,
|
||||||
|
token: &SyntaxToken,
|
||||||
|
) -> Option<(hir::Callable, Option<usize>)> {
|
||||||
let callable = match &calling_node {
|
let callable = match &calling_node {
|
||||||
ast::CallableExpr::Call(call) => {
|
ast::CallableExpr::Call(call) => {
|
||||||
let expr = call.expr()?;
|
let expr = call.expr()?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue