Fix active parameter analysis once more

This commit is contained in:
Lukas Wirth 2023-02-12 17:25:32 +01:00
parent d2cf8c234a
commit 9738f97f8c
2 changed files with 44 additions and 32 deletions

View File

@ -2,10 +2,10 @@
use either::Either;
use hir::{Semantics, Type};
use parser::T;
use syntax::{
algo::non_trivia_sibling,
ast::{self, HasArgList, HasName},
AstNode, Direction, SyntaxToken, TextRange,
AstNode, NodeOrToken, SyntaxToken,
};
use crate::RootDatabase;
@ -59,7 +59,7 @@ pub fn callable_for_node(
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) => {
let expr = call.expr()?;
sema.type_of_expr(&expr)?.adjusted().as_callable(sema.db)
@ -67,24 +67,15 @@ pub fn callable_for_node(
ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call),
}?;
let active_param = if let Some(arg_list) = calling_node.arg_list() {
let account_for_ws = |arg: &ast::Expr| {
let node = arg.syntax().clone();
let left = non_trivia_sibling(node.clone().into(), Direction::Prev)
.and_then(|it| it.into_token())?
.text_range();
let right = non_trivia_sibling(node.into(), Direction::Next)
.and_then(|it| it.into_token())?
.text_range();
Some(TextRange::new(left.end(), right.start()))
};
arg_list
.args()
.position(|arg| {
account_for_ws(&arg)
.unwrap_or(arg.syntax().text_range())
.contains(token.text_range().start())
})
.or(Some(0))
Some(
arg_list
.syntax()
.children_with_tokens()
.filter_map(NodeOrToken::into_token)
.filter(|t| t.kind() == T![,])
.take_while(|t| t.text_range().start() <= token.text_range().start())
.count(),
)
} else {
None
};

View File

@ -12,7 +12,7 @@ use stdx::format_to;
use syntax::{
algo,
ast::{self, HasArgList},
match_ast, AstNode, Direction, SyntaxKind, SyntaxToken, TextRange, TextSize,
match_ast, AstNode, Direction, SyntaxToken, TextRange, TextSize,
};
use crate::RootDatabase;
@ -105,10 +105,10 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio
// 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')
&& expr.syntax().kind() != SyntaxKind::RECORD_EXPR
if !matches!(expr, ast::Expr::RecordExpr(..))
&& expr.syntax().text().contains_char('\n')
{
return None;
break;
}
}
}
@ -122,18 +122,16 @@ fn signature_help_for_call(
token: SyntaxToken,
) -> Option<SignatureHelp> {
// Find the calling expression and its NameRef
let mut node = arg_list.syntax().parent()?;
let mut nodes = arg_list.syntax().ancestors().skip(1);
let calling_node = loop {
if let Some(callable) = ast::CallableExpr::cast(node.clone()) {
if callable
if let Some(callable) = ast::CallableExpr::cast(nodes.next()?) {
let inside_callable = callable
.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()));
if inside_callable {
break callable;
}
}
node = node.parent()?;
};
let (callable, active_parameter) = callable_for_node(sema, &calling_node, &token)?;
@ -1594,4 +1592,27 @@ impl S {
"#]],
);
}
#[test]
fn test_enum_in_nested_method_in_lambda() {
check(
r#"
enum A {
A,
B
}
fn bar(_: A) { }
fn main() {
let foo = Foo;
std::thread::spawn(move || { bar(A:$0) } );
}
"#,
expect![[r#"
fn bar(_: A)
^^^^
"#]],
);
}
}