Skip to content

Commit e08b3bf

Browse files
bors[bot]Veykril
andauthored
Merge #10231
10231: feat: Make inlay hints work in attributed items r=Veykril a=Veykril ![image](https://user-images.githubusercontent.com/3757771/133172697-8563329f-e77e-46e4-86ab-99b50040dfd5.png) Note the lack of chaining hints, this is currently due to macro expansion lacking the input whitespace. We might be able to recover this from the input somehow in the future. Fixes #10043 bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents 4261723 + e193e3b commit e08b3bf

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)