Unnamed repository; edit this file 'description' to name the repository.
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 https://github.com/rust-analyzer/rust-analyzer/issues/10043 bors r+ Co-authored-by: Lukas Wirth <[email protected]>
bors[bot] 2021-09-14
parent 4261723 · parent e193e3b · commit e08b3bf
-rw-r--r--crates/hir/src/semantics.rs1
-rw-r--r--crates/ide/src/inlay_hints.rs113
2 files changed, 98 insertions, 16 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index aaa9e308f1..ed27f6122b 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -211,6 +211,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
) -> impl Iterator<Item = SyntaxNode> + '_ {
token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it))
}
+
pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
self.imp.ancestors_with_macros(node)
}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index b2a8e2a209..cca3bb3fa8 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -64,17 +64,35 @@ pub(crate) fn inlay_hints(
let file = sema.parse(file_id);
let mut res = Vec::new();
- for node in file.syntax().descendants() {
- if let Some(expr) = ast::Expr::cast(node.clone()) {
- get_chaining_hints(&mut res, &sema, config, expr);
- }
+ let mut queue = vec![file.syntax().preorder()];
- match_ast! {
- match node {
- ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
- ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
- ast::IdentPat(it) => { get_bind_pat_hints(&mut res, &sema, config, it); },
- _ => (),
+ while let Some(mut preorder) = queue.pop() {
+ while let Some(event) = preorder.next() {
+ let node = match event {
+ syntax::WalkEvent::Enter(node) => node,
+ syntax::WalkEvent::Leave(_) => continue,
+ };
+ if let Some(node) =
+ ast::Item::cast(node.clone()).and_then(|item| sema.expand_attr_macro(&item))
+ {
+ preorder.skip_subtree();
+ queue.push(node.preorder());
+ continue;
+ }
+
+ if let Some(expr) = ast::Expr::cast(node.clone()) {
+ get_chaining_hints(&mut res, &sema, config, &expr);
+ match expr {
+ ast::Expr::CallExpr(it) => {
+ get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
+ }
+ ast::Expr::MethodCallExpr(it) => {
+ get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
+ }
+ _ => (),
+ }
+ } else if let Some(it) = ast::IdentPat::cast(node.clone()) {
+ get_bind_pat_hints(&mut res, &sema, config, it);
}
}
}
@@ -85,7 +103,7 @@ fn get_chaining_hints(
acc: &mut Vec<InlayHint>,
sema: &Semantics<RootDatabase>,
config: &InlayHintsConfig,
- expr: ast::Expr,
+ expr: &ast::Expr,
) -> Option<()> {
if !config.chaining_hints {
return None;
@@ -117,7 +135,7 @@ fn get_chaining_hints(
next_next = tokens.next()?.kind();
}
if next_next == T![.] {
- let ty = sema.type_of_expr(&expr)?.original;
+ let ty = sema.type_of_expr(expr)?.original;
if ty.is_unknown() {
return None;
}
@@ -129,7 +147,7 @@ fn get_chaining_hints(
}
}
acc.push(InlayHint {
- range: expr.syntax().text_range(),
+ range: sema.original_range(expr.syntax()).range,
kind: InlayKind::ChainingHint,
label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
ty.display_truncated(sema.db, config.max_length).to_string().into()
@@ -167,7 +185,7 @@ fn get_param_name_hints(
})
.filter(|(param_name, arg)| !should_hide_param_name_hint(sema, &callable, param_name, arg))
.map(|(param_name, arg)| InlayHint {
- range: arg.syntax().text_range(),
+ range: sema.original_range(arg.syntax()).range,
kind: InlayKind::ParameterHint,
label: param_name.into(),
});
@@ -197,8 +215,8 @@ fn get_bind_pat_hints(
acc.push(InlayHint {
range: match pat.name() {
- Some(name) => name.syntax().text_range(),
- None => pat.syntax().text_range(),
+ Some(name) => sema.original_range(name.syntax()).range,
+ None => sema.original_range(pat.syntax()).range,
},
kind: InlayKind::TypeHint,
label: hint_iterator(sema, &famous_defs, config, &ty)
@@ -1467,4 +1485,67 @@ fn main() {
"#]],
);
}
+
+ #[test]
+ fn hints_in_attr_call() {
+ // chaining hints do not currently work as macros lose all whitespace information
+ check_expect(
+ TEST_CONFIG,
+ r#"
+//- proc_macros: identity, input_replace
+struct Struct;
+impl Struct {
+ fn chain(self) -> Self {
+ self
+ }
+}
+
+#[proc_macros::identity]
+fn main() {
+ let strukt = Struct;
+ strukt
+ .chain()
+ .chain()
+ .chain();
+ Struct::chain(strukt);
+}
+
+#[proc_macros::input_replace(
+ fn not_main() {
+ let strukt = Struct;
+ strukt
+ .chain()
+ .chain()
+ .chain();
+ Struct::chain(strukt);
+ }
+)]
+fn main() {}
+"#,
+ expect![[r#"
+ [
+ InlayHint {
+ range: 297..303,
+ kind: TypeHint,
+ label: "Struct",
+ },
+ InlayHint {
+ range: 415..421,
+ kind: ParameterHint,
+ label: "self",
+ },
+ InlayHint {
+ range: 125..131,
+ kind: TypeHint,
+ label: "Struct",
+ },
+ InlayHint {
+ range: 223..229,
+ kind: ParameterHint,
+ label: "self",
+ },
+ ]
+ "#]],
+ );
+ }
}