Skip to content

Commit

Permalink
fix: Fix lifetime elision inlay hints breaking for ranged requests
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Aug 31, 2024
1 parent 1607797 commit 82f96b5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 57 deletions.
114 changes: 58 additions & 56 deletions crates/ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use span::{Edition, EditionedFileId};
use stdx::never;
use syntax::{
ast::{self, AstNode, HasGenericParams},
format_smolstr, match_ast, NodeOrToken, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
};
use text_edit::TextEdit;

Expand Down Expand Up @@ -95,26 +95,27 @@ pub(crate) fn inlay_hints(
let famous_defs = FamousDefs(&sema, scope.krate());

let ctx = &mut InlayHintCtx::default();
let hints = |node| hints(&mut acc, ctx, &famous_defs, config, file_id, node);
match range_limit {
// FIXME: This can miss some hints that require the parent of the range to calculate
Some(range) => match file.covering_element(range) {
NodeOrToken::Token(_) => return acc,
NodeOrToken::Node(n) => n
.preorder()
.filter(|event| matches!(event, WalkEvent::Enter(node) if range.intersect(node.text_range()).is_some()))
.for_each(hints),
},
None => file.preorder().for_each(hints),
let mut hints = |event| {
if let Some(node) = handle_event(ctx, event) {
hints(&mut acc, ctx, &famous_defs, config, file_id, node);
}
};

let mut preorder = file.preorder();
while let Some(event) = preorder.next() {
// FIXME: This can miss some hints that require the parent of the range to calculate
if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none())
{
preorder.skip_subtree();
continue;
}
hints(event);
}
acc
}

#[derive(Default)]
struct InlayHintCtx {
lifetime_stacks: Vec<Vec<SmolStr>>,
is_param_list: bool,
}

pub(crate) fn inlay_hints_resolve(
Expand All @@ -138,20 +139,52 @@ pub(crate) fn inlay_hints_resolve(
let mut acc = Vec::new();

let ctx = &mut InlayHintCtx::default();
let hints = |node| hints(&mut acc, ctx, &famous_defs, config, file_id, node);

let mut res = file.clone();
let res = loop {
res = match res.child_or_token_at_range(resolve_range) {
Some(NodeOrToken::Node(n)) if n.text_range() == resolve_range => break n,
Some(NodeOrToken::Node(n)) => n,
_ => break res,
};
let mut hints = |event| {
if let Some(node) = handle_event(ctx, event) {
hints(&mut acc, ctx, &famous_defs, config, file_id, node);
}
};
res.preorder().for_each(hints);

let mut preorder = file.preorder();
while let Some(event) = preorder.next() {
// FIXME: This can miss some hints that require the parent of the range to calculate
if matches!(&event, WalkEvent::Enter(node) if resolve_range.intersect(node.text_range()).is_none())
{
preorder.skip_subtree();
continue;
}
hints(event);
}
acc.into_iter().find(|hint| hasher(hint) == hash)
}

fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent<SyntaxNode>) -> Option<SyntaxNode> {
match node {
WalkEvent::Enter(node) => {
if let Some(node) = ast::AnyHasGenericParams::cast(node.clone()) {
let params = node
.generic_param_list()
.map(|it| {
it.lifetime_params()
.filter_map(|it| {
it.lifetime().map(|it| format_smolstr!("{}", &it.text()[1..]))
})
.collect()
})
.unwrap_or_default();
ctx.lifetime_stacks.push(params);
}
Some(node)
}
WalkEvent::Leave(n) => {
if ast::AnyHasGenericParams::can_cast(n.kind()) {
ctx.lifetime_stacks.pop();
}
None
}
}
}

// FIXME: At some point when our hir infra is fleshed out enough we should flip this and traverse the
// HIR instead of the syntax tree.
fn hints(
Expand All @@ -160,35 +193,8 @@ fn hints(
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
config: &InlayHintsConfig,
file_id: EditionedFileId,
node: WalkEvent<SyntaxNode>,
node: SyntaxNode,
) {
let node = match node {
WalkEvent::Enter(node) => node,
WalkEvent::Leave(n) => {
if ast::AnyHasGenericParams::can_cast(n.kind()) {
ctx.lifetime_stacks.pop();
// pop
}
if ast::ParamList::can_cast(n.kind()) {
ctx.is_param_list = false;
// pop
}
return;
}
};

if let Some(node) = ast::AnyHasGenericParams::cast(node.clone()) {
let params = node
.generic_param_list()
.map(|it| {
it.lifetime_params()
.filter_map(|it| it.lifetime().map(|it| format_smolstr!("{}", &it.text()[1..])))
.collect()
})
.unwrap_or_default();
ctx.lifetime_stacks.push(params);
}

closing_brace::hints(hints, sema, config, file_id, node.clone());
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
generic_param::hints(hints, sema, config, any_has_generic_args);
Expand Down Expand Up @@ -242,10 +248,6 @@ fn hints(
ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path),
_ => Some(()),
},
ast::ParamList(_) => {
ctx.is_param_list = true;
Some(())
},
_ => Some(()),
}
};
Expand Down
2 changes: 1 addition & 1 deletion crates/ide/src/inlay_hints/lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ fn fn_ptr(a: fn(&()) -> &fn(&()) -> &()) {}
//^^ for<'1>
//^'1
//^'1
fn fn_ptr2(a: for<'a> fn(&()) -> &())) {}
fn fn_ptr2(a: for<'a> fn(&()) -> &()) {}
//^'0, $
//^'0
//^'0
Expand Down

0 comments on commit 82f96b5

Please sign in to comment.