WIP: See through Macros for SignatureHelp

Note: we meed to skip the trivia filter to make sure that
`covers!(call_info_bad_offset)` succeeds otherwise we exit call_info
too early.

Also the test doesn't pass: `FnCallNode::with_node` always detects
a MacroCall.
This commit is contained in:
kjeremy 2019-11-18 18:08:39 -05:00 committed by Jeremy Kolb
parent 242f0ae1d8
commit 7ec43ee07a

View file

@ -1,22 +1,22 @@
//! FIXME: write short doc here //! FIXME: write short doc here
use ra_db::SourceDatabase; use hir::db::AstDatabase;
use ra_syntax::{ use ra_syntax::{
algo::ancestors_at_offset,
ast::{self, ArgListOwner}, ast::{self, ArgListOwner},
match_ast, AstNode, SyntaxNode, TextUnit, match_ast, AstNode, SyntaxNode,
}; };
use test_utils::tested_by; use test_utils::tested_by;
use crate::{db::RootDatabase, CallInfo, FilePosition, FunctionSignature}; use crate::{db::RootDatabase, expand::descend_into_macros, CallInfo, FilePosition, FunctionSignature};
/// Computes parameter information for the given call expression. /// Computes parameter information for the given call expression.
pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
let parse = db.parse(position.file_id); let file = db.parse_or_expand(position.file_id.into())?;
let syntax = parse.tree().syntax().clone(); let token = file.token_at_offset(position.offset).next()?;
let token = descend_into_macros(db, position.file_id, token);
// Find the calling expression and it's NameRef // Find the calling expression and it's NameRef
let calling_node = FnCallNode::with_node(&syntax, position.offset)?; let calling_node = FnCallNode::with_node(&token.value.parent())?;
let name_ref = calling_node.name_ref()?; let name_ref = calling_node.name_ref()?;
let name_ref = hir::InFile::new(position.file_id.into(), name_ref.syntax()); let name_ref = hir::InFile::new(position.file_id.into(), name_ref.syntax());
@ -93,8 +93,8 @@ enum FnCallNode {
} }
impl FnCallNode { impl FnCallNode {
fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option<FnCallNode> { fn with_node(syntax: &SyntaxNode) -> Option<FnCallNode> {
ancestors_at_offset(syntax, offset).find_map(|node| { syntax.ancestors().find_map(|node| {
match_ast! { match_ast! {
match node { match node {
ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) }, ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) },
@ -589,4 +589,25 @@ fn f() {
assert_eq!(info.label(), "foo!()"); assert_eq!(info.label(), "foo!()");
assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string()));
} }
#[test]
fn fn_signature_for_call_in_macro() {
let info = call_info(
r#"
macro_rules! id {
($($tt:tt)*) => { $($tt)* }
}
fn foo() {
}
id! {
fn bar() {
foo(<|>);
}
}
"#,
);
assert_eq!(info.label(), "fn foo()");
}
} }