Add hover for closure

This commit is contained in:
hkalbasi 2023-04-30 14:31:43 +03:30
parent 370b72c7dd
commit 5df545b3f0
7 changed files with 249 additions and 7 deletions

View file

@ -119,8 +119,8 @@ fn hover_simple(
| T![crate]
| T![Self]
| T![_] => 4,
// index and prefix ops
T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
// index and prefix ops and closure pipe
T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] | T![|] => 3,
kind if kind.is_keyword() => 2,
T!['('] | T![')'] => 2,
kind if kind.is_trivia() => 0,
@ -219,6 +219,16 @@ fn hover_simple(
};
render::type_info_of(sema, config, &Either::Left(call_expr))
})
})
// try closure
.or_else(|| {
descended().find_map(|token| {
if token.kind() != T![|] {
return None;
}
let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?;
render::closure_expr(sema, c)
})
});
result.map(|mut res: HoverResult| {

View file

@ -42,6 +42,38 @@ pub(super) fn type_info_of(
type_info(sema, _config, original, adjusted)
}
pub(super) fn closure_expr(
sema: &Semantics<'_, RootDatabase>,
c: ast::ClosureExpr,
) -> Option<HoverResult> {
let ty = &sema.type_of_expr(&c.into())?.original;
let layout = ty
.layout(sema.db)
.map(|x| format!(" // size = {}, align = {}", x.size.bytes(), x.align.abi.bytes()))
.unwrap_or_default();
let c = ty.as_closure()?;
let mut captures = c
.captured_items(sema.db)
.into_iter()
.map(|x| {
format!("* `{}` by {}", x.display_place(c.clone().into(), sema.db), x.display_kind())
})
.join("\n");
if captures.trim().is_empty() {
captures = "This closure captures nothing".to_string();
}
let mut res = HoverResult::default();
res.markup = format!(
"```rust\n{}{}\n{}\n```\n\n## Captures\n{}",
c.display_with_id(sema.db),
layout,
c.display_with_impl(sema.db),
captures,
)
.into();
Some(res)
}
pub(super) fn try_expr(
sema: &Semantics<'_, RootDatabase>,
_config: &HoverConfig,

View file

@ -198,6 +198,85 @@ fn main() {
);
}
#[test]
fn hover_closure() {
check(
r#"
//- minicore: copy
fn main() {
let x = 2;
let y = $0|z| x + z;
}
"#,
expect![[r#"
*|*
```rust
{closure#0} // size = 8, align = 8
impl Fn(i32) -> i32
```
## Captures
* `x` by immutable borrow
"#]],
);
check(
r#"
//- minicore: copy
fn foo(x: impl Fn(i32) -> i32) {
}
fn main() {
foo($0|x: i32| x)
}
"#,
expect![[r#"
*|*
```rust
{closure#0} // size = 0, align = 1
impl Fn(i32) -> i32
```
## Captures
This closure captures nothing
"#]],
);
check(
r#"
//- minicore: copy
struct Z { f: i32 }
struct Y(&'static mut Z)
struct X {
f1: Y,
f2: (Y, Y),
}
fn main() {
let x: X;
let y = $0|| {
x.f1;
&mut x.f2.0 .0.f;
};
}
"#,
expect![[r#"
*|*
```rust
{closure#0} // size = 16, align = 8
impl FnOnce()
```
## Captures
* `x.f1` by move
* `(*x.f2.0.0).f` by mutable borrow
"#]],
);
}
#[test]
fn hover_shows_long_type_of_an_expression() {
check(