fix: Fix callHierarchy LSP violation

This commit is contained in:
Lukas Wirth 2024-07-07 10:14:47 +02:00
parent 8a4b1fd96e
commit 6c8c49b01b
2 changed files with 187 additions and 31 deletions

View file

@ -9,14 +9,15 @@ use ide_db::{
search::FileReference, search::FileReference,
FxIndexMap, RootDatabase, FxIndexMap, RootDatabase,
}; };
use syntax::{ast, AstNode, SyntaxKind::IDENT, TextRange}; use span::FileRange;
use syntax::{ast, AstNode, SyntaxKind::IDENT};
use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav}; use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CallItem { pub struct CallItem {
pub target: NavigationTarget, pub target: NavigationTarget,
pub ranges: Vec<TextRange>, pub ranges: Vec<FileRange>,
} }
pub(crate) fn call_hierarchy( pub(crate) fn call_hierarchy(
@ -61,9 +62,10 @@ pub(crate) fn incoming_calls(
def.try_to_nav(sema.db) def.try_to_nav(sema.db)
}); });
if let Some(nav) = nav { if let Some(nav) = nav {
calls.add(nav.call_site, sema.original_range(name.syntax()).range); let range = sema.original_range(name.syntax());
calls.add(nav.call_site, range);
if let Some(other) = nav.def_site { if let Some(other) = nav.def_site {
calls.add(other, sema.original_range(name.syntax()).range); calls.add(other, range);
} }
} }
} }
@ -107,12 +109,13 @@ pub(crate) fn outgoing_calls(
hir::CallableKind::TupleStruct(it) => it.try_to_nav(db), hir::CallableKind::TupleStruct(it) => it.try_to_nav(db),
_ => None, _ => None,
} }
.zip(Some(expr.syntax().text_range())) .zip(Some(sema.original_range(expr.syntax())))
} }
ast::CallableExpr::MethodCall(expr) => { ast::CallableExpr::MethodCall(expr) => {
let range = expr.name_ref()?.syntax().text_range();
let function = sema.resolve_method_call(&expr)?; let function = sema.resolve_method_call(&expr)?;
function.try_to_nav(db).zip(Some(range)) function
.try_to_nav(db)
.zip(Some(sema.original_range(expr.name_ref()?.syntax())))
} }
}?; }?;
Some(nav_target.into_iter().zip(iter::repeat(range))) Some(nav_target.into_iter().zip(iter::repeat(range)))
@ -125,11 +128,11 @@ pub(crate) fn outgoing_calls(
#[derive(Default)] #[derive(Default)]
struct CallLocations { struct CallLocations {
funcs: FxIndexMap<NavigationTarget, Vec<TextRange>>, funcs: FxIndexMap<NavigationTarget, Vec<FileRange>>,
} }
impl CallLocations { impl CallLocations {
fn add(&mut self, target: NavigationTarget, range: TextRange) { fn add(&mut self, target: NavigationTarget, range: FileRange) {
self.funcs.entry(target).or_default().push(range); self.funcs.entry(target).or_default().push(range);
} }
@ -153,7 +156,14 @@ mod tests {
expected_outgoing: Expect, expected_outgoing: Expect,
) { ) {
fn debug_render(item: crate::CallItem) -> String { fn debug_render(item: crate::CallItem) -> String {
format!("{} : {:?}", item.target.debug_render(), item.ranges) format!(
"{} : {}",
item.target.debug_render(),
item.ranges.iter().format_with(", ", |range, f| f(&format_args!(
"{:?}:{:?}",
range.file_id, range.range
)))
)
} }
let (analysis, pos) = fixture::position(ra_fixture); let (analysis, pos) = fixture::position(ra_fixture);
@ -183,7 +193,7 @@ fn caller() {
} }
"#, "#,
expect![["callee Function FileId(0) 0..14 3..9"]], expect![["callee Function FileId(0) 0..14 3..9"]],
expect![["caller Function FileId(0) 15..44 18..24 : [33..39]"]], expect!["caller Function FileId(0) 15..44 18..24 : FileId(0):33..39"],
expect![[]], expect![[]],
); );
} }
@ -199,7 +209,7 @@ fn caller() {
} }
"#, "#,
expect![["callee Function FileId(0) 0..14 3..9"]], expect![["callee Function FileId(0) 0..14 3..9"]],
expect![["caller Function FileId(0) 15..44 18..24 : [33..39]"]], expect!["caller Function FileId(0) 15..44 18..24 : FileId(0):33..39"],
expect![[]], expect![[]],
); );
} }
@ -216,7 +226,7 @@ fn caller() {
} }
"#, "#,
expect![["callee Function FileId(0) 0..14 3..9"]], expect![["callee Function FileId(0) 0..14 3..9"]],
expect![["caller Function FileId(0) 15..58 18..24 : [33..39, 47..53]"]], expect!["caller Function FileId(0) 15..58 18..24 : FileId(0):33..39, FileId(0):47..53"],
expect![[]], expect![[]],
); );
} }
@ -236,9 +246,9 @@ fn caller2() {
} }
"#, "#,
expect![["callee Function FileId(0) 0..14 3..9"]], expect![["callee Function FileId(0) 0..14 3..9"]],
expect![[" expect![[r#"
caller1 Function FileId(0) 15..45 18..25 : [34..40] caller1 Function FileId(0) 15..45 18..25 : FileId(0):34..40
caller2 Function FileId(0) 47..77 50..57 : [66..72]"]], caller2 Function FileId(0) 47..77 50..57 : FileId(0):66..72"#]],
expect![[]], expect![[]],
); );
} }
@ -265,8 +275,8 @@ mod tests {
"#, "#,
expect![["callee Function FileId(0) 0..14 3..9"]], expect![["callee Function FileId(0) 0..14 3..9"]],
expect![[r#" expect![[r#"
caller1 Function FileId(0) 15..45 18..25 : [34..40] caller1 Function FileId(0) 15..45 18..25 : FileId(0):34..40
test_caller Function FileId(0) 95..149 110..121 tests : [134..140]"#]], test_caller Function FileId(0) 95..149 110..121 tests : FileId(0):134..140"#]],
expect![[]], expect![[]],
); );
} }
@ -287,7 +297,7 @@ fn caller() {
pub fn callee() {} pub fn callee() {}
"#, "#,
expect!["callee Function FileId(1) 0..18 7..13 foo"], expect!["callee Function FileId(1) 0..18 7..13 foo"],
expect![["caller Function FileId(0) 27..56 30..36 : [45..51]"]], expect!["caller Function FileId(0) 27..56 30..36 : FileId(0):45..51"],
expect![[]], expect![[]],
); );
} }
@ -305,7 +315,7 @@ fn call$0er() {
"#, "#,
expect![["caller Function FileId(0) 15..58 18..24"]], expect![["caller Function FileId(0) 15..58 18..24"]],
expect![[]], expect![[]],
expect![["callee Function FileId(0) 0..14 3..9 : [33..39, 47..53]"]], expect!["callee Function FileId(0) 0..14 3..9 : FileId(0):33..39, FileId(0):47..53"],
); );
} }
@ -326,7 +336,7 @@ pub fn callee() {}
"#, "#,
expect![["caller Function FileId(0) 27..56 30..36"]], expect![["caller Function FileId(0) 27..56 30..36"]],
expect![[]], expect![[]],
expect!["callee Function FileId(1) 0..18 7..13 foo : [45..51]"], expect!["callee Function FileId(1) 0..18 7..13 foo : FileId(0):45..51"],
); );
} }
@ -348,8 +358,8 @@ fn caller3() {
} }
"#, "#,
expect![["caller2 Function FileId(0) 33..64 36..43"]], expect![["caller2 Function FileId(0) 33..64 36..43"]],
expect![["caller1 Function FileId(0) 0..31 3..10 : [19..26]"]], expect!["caller1 Function FileId(0) 0..31 3..10 : FileId(0):19..26"],
expect![["caller3 Function FileId(0) 66..83 69..76 : [52..59]"]], expect!["caller3 Function FileId(0) 66..83 69..76 : FileId(0):52..59"],
); );
} }
@ -368,8 +378,8 @@ fn main() {
} }
"#, "#,
expect![["a Function FileId(0) 0..18 3..4"]], expect![["a Function FileId(0) 0..18 3..4"]],
expect![["main Function FileId(0) 31..52 34..38 : [47..48]"]], expect!["main Function FileId(0) 31..52 34..38 : FileId(0):47..48"],
expect![["b Function FileId(0) 20..29 23..24 : [13..14]"]], expect!["b Function FileId(0) 20..29 23..24 : FileId(0):13..14"],
); );
check_hierarchy( check_hierarchy(
@ -385,7 +395,7 @@ fn main() {
} }
"#, "#,
expect![["b Function FileId(0) 20..29 23..24"]], expect![["b Function FileId(0) 20..29 23..24"]],
expect![["a Function FileId(0) 0..18 3..4 : [13..14]"]], expect!["a Function FileId(0) 0..18 3..4 : FileId(0):13..14"],
expect![[]], expect![[]],
); );
} }
@ -410,7 +420,7 @@ fn caller() {
} }
"#, "#,
expect![[r#"callee Function FileId(0) 144..159 152..158"#]], expect![[r#"callee Function FileId(0) 144..159 152..158"#]],
expect![[r#"caller Function FileId(0) 160..194 163..169 : [184..190]"#]], expect!["caller Function FileId(0) 160..194 163..169 : FileId(0):184..190"],
expect![[]], expect![[]],
); );
check_hierarchy( check_hierarchy(
@ -431,7 +441,7 @@ fn caller() {
} }
"#, "#,
expect![[r#"callee Function FileId(0) 144..159 152..158"#]], expect![[r#"callee Function FileId(0) 144..159 152..158"#]],
expect![[r#"caller Function FileId(0) 160..194 163..169 : [184..190]"#]], expect!["caller Function FileId(0) 160..194 163..169 : FileId(0):184..190"],
expect![[]], expect![[]],
); );
} }
@ -461,6 +471,148 @@ fn caller$0() {
expect![[]], expect![[]],
); );
} }
#[test]
fn test_call_hierarchy_in_macros_incoming_different_files() {
check_hierarchy(
r#"
//- /lib.rs
#[macro_use]
mod foo;
define!(callee)
fn caller() {
call!(call$0ee);
}
//- /foo.rs
macro_rules! define {
($ident:ident) => {
fn $ident {}
}
}
macro_rules! call {
($ident:ident) => {
$ident()
}
}
"#,
expect!["callee Function FileId(0) 22..37 30..36"],
expect!["caller Function FileId(0) 38..72 41..47 : FileId(0):62..68"],
expect![[]],
);
check_hierarchy(
r#"
//- /lib.rs
#[macro_use]
mod foo;
define!(cal$0lee)
fn caller() {
call!(callee);
}
//- /foo.rs
macro_rules! define {
($ident:ident) => {
fn $ident {}
}
}
macro_rules! call {
($ident:ident) => {
$ident()
}
}
"#,
expect!["callee Function FileId(0) 22..37 30..36"],
expect!["caller Function FileId(0) 38..72 41..47 : FileId(0):62..68"],
expect![[]],
);
check_hierarchy(
r#"
//- /lib.rs
#[macro_use]
mod foo;
define!(cal$0lee)
call!(callee);
//- /foo.rs
macro_rules! define {
($ident:ident) => {
fn $ident {}
}
}
macro_rules! call {
($ident:ident) => {
fn caller() {
$ident()
}
fn $ident() {
$ident()
}
}
}
"#,
expect!["callee Function FileId(0) 22..37 30..36"],
expect![[r#"
callee Function FileId(0) 38..52 44..50 : FileId(0):44..50
caller Function FileId(0) 38..52 : FileId(0):44..50
caller Function FileId(1) 130..136 130..136 : FileId(0):44..50"#]],
expect![[]],
);
}
#[test]
fn test_call_hierarchy_in_macros_outgoing_different_files() {
check_hierarchy(
r#"
//- /lib.rs
#[macro_use]
mod foo;
define!(callee)
fn caller$0() {
call!(callee);
}
//- /foo.rs
macro_rules! define {
($ident:ident) => {
fn $ident {}
}
}
macro_rules! call {
($ident:ident) => {
$ident()
callee()
}
}
"#,
expect!["caller Function FileId(0) 38..72 41..47"],
expect![[]],
// FIXME
expect![[]],
);
check_hierarchy(
r#"
//- /lib.rs
#[macro_use]
mod foo;
define!(callee)
fn caller$0() {
call!(callee);
}
//- /foo.rs
macro_rules! define {
() => {
fn callee {}
}
}
macro_rules! call {
($ident:ident) => {
$ident()
callee()
}
}
"#,
expect!["caller Function FileId(0) 38..72 41..47"],
expect![[]],
// FIXME
expect![[]],
);
}
#[test] #[test]
fn test_trait_method_call_hierarchy() { fn test_trait_method_call_hierarchy() {
@ -481,7 +633,7 @@ fn caller() {
} }
"#, "#,
expect!["callee Function FileId(0) 15..27 18..24 T1"], expect!["callee Function FileId(0) 15..27 18..24 T1"],
expect![["caller Function FileId(0) 82..115 85..91 : [104..110]"]], expect!["caller Function FileId(0) 82..115 85..91 : FileId(0):104..110"],
expect![[]], expect![[]],
); );
} }

View file

@ -1640,7 +1640,9 @@ pub(crate) fn handle_call_hierarchy_incoming(
from_ranges: call_item from_ranges: call_item
.ranges .ranges
.into_iter() .into_iter()
.map(|it| to_proto::range(&line_index, it)) // This is the range relative to the item
.filter(|it| it.file_id == file_id)
.map(|it| to_proto::range(&line_index, it.range))
.collect(), .collect(),
}); });
} }
@ -1675,7 +1677,9 @@ pub(crate) fn handle_call_hierarchy_outgoing(
from_ranges: call_item from_ranges: call_item
.ranges .ranges
.into_iter() .into_iter()
.map(|it| to_proto::range(&line_index, it)) // This is the range relative to the caller
.filter(|it| it.file_id == fpos.file_id)
.map(|it| to_proto::range(&line_index, it.range))
.collect(), .collect(),
}); });
} }