From 7ec43ee07a26667bb1458990ec667f82670aff22 Mon Sep 17 00:00:00 2001
From: kjeremy <kjeremy@gmail.com>
Date: Mon, 18 Nov 2019 18:08:39 -0500
Subject: [PATCH] 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.
---
 crates/ra_ide/src/call_info.rs | 39 ++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index b3c323d38c7..2da9c4e7657 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,22 +1,22 @@
 //! FIXME: write short doc here
 
-use ra_db::SourceDatabase;
+use hir::db::AstDatabase;
 use ra_syntax::{
-    algo::ancestors_at_offset,
     ast::{self, ArgListOwner},
-    match_ast, AstNode, SyntaxNode, TextUnit,
+    match_ast, AstNode, SyntaxNode,
 };
 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.
 pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
-    let parse = db.parse(position.file_id);
-    let syntax = parse.tree().syntax().clone();
+    let file = db.parse_or_expand(position.file_id.into())?;
+    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
-    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 = hir::InFile::new(position.file_id.into(), name_ref.syntax());
 
@@ -93,8 +93,8 @@ enum FnCallNode {
 }
 
 impl FnCallNode {
-    fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option<FnCallNode> {
-        ancestors_at_offset(syntax, offset).find_map(|node| {
+    fn with_node(syntax: &SyntaxNode) -> Option<FnCallNode> {
+        syntax.ancestors().find_map(|node| {
             match_ast! {
                 match node {
                     ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) },
@@ -589,4 +589,25 @@ fn f() {
         assert_eq!(info.label(), "foo!()");
         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()");
+    }
 }