Skip to content

Commit e193e3b

Browse files
committed
feat: Make inlay hints work in attributed items
1 parent 8f76e41 commit e193e3b

File tree

2 files changed

+98
-16
lines changed

2 files changed

+98
-16
lines changed

crates/hir/src/semantics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
211211
) -> impl Iterator<Item = SyntaxNode> + '_ {
212212
token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it))
213213
}
214+
214215
pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
215216
self.imp.ancestors_with_macros(node)
216217
}

crates/ide/src/inlay_hints.rs

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,35 @@ pub(crate) fn inlay_hints(
6464
let file = sema.parse(file_id);
6565

6666
let mut res = Vec::new();
67-
for node in file.syntax().descendants() {
68-
if let Some(expr) = ast::Expr::cast(node.clone()) {
69-
get_chaining_hints(&mut res, &sema, config, expr);
70-
}
67+
let mut queue = vec![file.syntax().preorder()];
7168

72-
match_ast! {
73-
match node {
74-
ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
75-
ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
76-
ast::IdentPat(it) => { get_bind_pat_hints(&mut res, &sema, config, it); },
77-
_ => (),
69+
while let Some(mut preorder) = queue.pop() {
70+
while let Some(event) = preorder.next() {
71+
let node = match event {
72+
syntax::WalkEvent::Enter(node) => node,
73+
syntax::WalkEvent::Leave(_) => continue,
74+
};
75+
if let Some(node) =
76+
ast::Item::cast(node.clone()).and_then(|item| sema.expand_attr_macro(&item))
77+
{
78+
preorder.skip_subtree();
79+
queue.push(node.preorder());
80+
continue;
81+
}
82+
83+
if let Some(expr) = ast::Expr::cast(node.clone()) {
84+
get_chaining_hints(&mut res, &sema, config, &expr);
85+
match expr {
86+
ast::Expr::CallExpr(it) => {
87+
get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
88+
}
89+
ast::Expr::MethodCallExpr(it) => {
90+
get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
91+
}
92+
_ => (),
93+
}
94+
} else if let Some(it) = ast::IdentPat::cast(node.clone()) {
95+
get_bind_pat_hints(&mut res, &sema, config, it);
7896
}
7997
}
8098
}
@@ -85,7 +103,7 @@ fn get_chaining_hints(
85103
acc: &mut Vec<InlayHint>,
86104
sema: &Semantics<RootDatabase>,
87105
config: &InlayHintsConfig,
88-
expr: ast::Expr,
106+
expr: &ast::Expr,
89107
) -> Option<()> {
90108
if !config.chaining_hints {
91109
return None;
@@ -117,7 +135,7 @@ fn get_chaining_hints(
117135
next_next = tokens.next()?.kind();
118136
}
119137
if next_next == T![.] {
120-
let ty = sema.type_of_expr(&expr)?.original;
138+
let ty = sema.type_of_expr(expr)?.original;
121139
if ty.is_unknown() {
122140
return None;
123141
}
@@ -129,7 +147,7 @@ fn get_chaining_hints(
129147
}
130148
}
131149
acc.push(InlayHint {
132-
range: expr.syntax().text_range(),
150+
range: sema.original_range(expr.syntax()).range,
133151
kind: InlayKind::ChainingHint,
134152
label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
135153
ty.display_truncated(sema.db, config.max_length).to_string().into()
@@ -167,7 +185,7 @@ fn get_param_name_hints(
167185
})
168186
.filter(|(param_name, arg)| !should_hide_param_name_hint(sema, &callable, param_name, arg))
169187
.map(|(param_name, arg)| InlayHint {
170-
range: arg.syntax().text_range(),
188+
range: sema.original_range(arg.syntax()).range,
171189
kind: InlayKind::ParameterHint,
172190
label: param_name.into(),
173191
});
@@ -197,8 +215,8 @@ fn get_bind_pat_hints(
197215

198216
acc.push(InlayHint {
199217
range: match pat.name() {
200-
Some(name) => name.syntax().text_range(),
201-
None => pat.syntax().text_range(),
218+
Some(name) => sema.original_range(name.syntax()).range,
219+
None => sema.original_range(pat.syntax()).range,
202220
},
203221
kind: InlayKind::TypeHint,
204222
label: hint_iterator(sema, &famous_defs, config, &ty)
@@ -1467,4 +1485,67 @@ fn main() {
14671485
"#]],
14681486
);
14691487
}
1488+
1489+
#[test]
1490+
fn hints_in_attr_call() {
1491+
// chaining hints do not currently work as macros lose all whitespace information
1492+
check_expect(
1493+
TEST_CONFIG,
1494+
r#"
1495+
//- proc_macros: identity, input_replace
1496+
struct Struct;
1497+
impl Struct {
1498+
fn chain(self) -> Self {
1499+
self
1500+
}
1501+
}
1502+
1503+
#[proc_macros::identity]
1504+
fn main() {
1505+
let strukt = Struct;
1506+
strukt
1507+
.chain()
1508+
.chain()
1509+
.chain();
1510+
Struct::chain(strukt);
1511+
}
1512+
1513+
#[proc_macros::input_replace(
1514+
fn not_main() {
1515+
let strukt = Struct;
1516+
strukt
1517+
.chain()
1518+
.chain()
1519+
.chain();
1520+
Struct::chain(strukt);
1521+
}
1522+
)]
1523+
fn main() {}
1524+
"#,
1525+
expect![[r#"
1526+
[
1527+
InlayHint {
1528+
range: 297..303,
1529+
kind: TypeHint,
1530+
label: "Struct",
1531+
},
1532+
InlayHint {
1533+
range: 415..421,
1534+
kind: ParameterHint,
1535+
label: "self",
1536+
},
1537+
InlayHint {
1538+
range: 125..131,
1539+
kind: TypeHint,
1540+
label: "Struct",
1541+
},
1542+
InlayHint {
1543+
range: 223..229,
1544+
kind: ParameterHint,
1545+
label: "self",
1546+
},
1547+
]
1548+
"#]],
1549+
);
1550+
}
14701551
}

0 commit comments

Comments
 (0)