summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
blob: d9929beaac0c247bb258962067ba40e01fc2bd48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//! Implementation of "closure return type" inlay hints.
use ide_db::{base_db::FileId, famous_defs::FamousDefs};
use syntax::ast::{self, AstNode};

use crate::{
    inlay_hints::closure_has_block_body, ClosureReturnTypeHints, InlayHint, InlayHintsConfig,
    InlayKind, InlayTooltip,
};

use super::label_of_ty;

pub(super) fn hints(
    acc: &mut Vec<InlayHint>,
    famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
    config: &InlayHintsConfig,
    file_id: FileId,
    closure: ast::ClosureExpr,
) -> Option<()> {
    if config.closure_return_type_hints == ClosureReturnTypeHints::Never {
        return None;
    }

    if closure.ret_type().is_some() {
        return None;
    }

    if !closure_has_block_body(&closure)
        && config.closure_return_type_hints == ClosureReturnTypeHints::WithBlock
    {
        return None;
    }

    let param_list = closure.param_list()?;

    let closure = sema.descend_node_into_attributes(closure).pop()?;
    let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
    let callable = ty.as_callable(sema.db)?;
    let ty = callable.return_type();
    if ty.is_unit() {
        return None;
    }
    acc.push(InlayHint {
        range: param_list.syntax().text_range(),
        kind: InlayKind::ClosureReturnTypeHint,
        label: label_of_ty(famous_defs, config, ty)?,
        tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
    });
    Some(())
}