]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/inlay_hints/binding_mode.rs
Auto merge of #13764 - WaffleLapkin:badassexprs, r=Veykril
[rust.git] / crates / ide / src / inlay_hints / binding_mode.rs
1 //! Implementation of "binding mode" inlay hints:
2 //! ```no_run
3 //! let /* & */ (/* ref */ x,) = &(0,);
4 //! ```
5 use hir::{Mutability, Semantics};
6 use ide_db::RootDatabase;
7
8 use syntax::ast::{self, AstNode};
9
10 use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip};
11
12 pub(super) fn hints(
13     acc: &mut Vec<InlayHint>,
14     sema: &Semantics<'_, RootDatabase>,
15     config: &InlayHintsConfig,
16     pat: &ast::Pat,
17 ) -> Option<()> {
18     if !config.binding_mode_hints {
19         return None;
20     }
21
22     let outer_paren_pat = pat
23         .syntax()
24         .ancestors()
25         .skip(1)
26         .map_while(ast::Pat::cast)
27         .map_while(|pat| match pat {
28             ast::Pat::ParenPat(pat) => Some(pat),
29             _ => None,
30         })
31         .last();
32     let range =
33         outer_paren_pat.as_ref().map_or_else(|| pat.syntax(), |it| it.syntax()).text_range();
34     sema.pattern_adjustments(&pat).iter().for_each(|ty| {
35         let reference = ty.is_reference();
36         let mut_reference = ty.is_mutable_reference();
37         let r = match (reference, mut_reference) {
38             (true, true) => "&mut",
39             (true, false) => "&",
40             _ => return,
41         };
42         acc.push(InlayHint {
43             range,
44             kind: InlayKind::BindingModeHint,
45             label: r.to_string().into(),
46             tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
47         });
48     });
49     match pat {
50         ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
51             let bm = sema.binding_mode_of_pat(pat)?;
52             let bm = match bm {
53                 hir::BindingMode::Move => return None,
54                 hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
55                 hir::BindingMode::Ref(Mutability::Shared) => "ref",
56             };
57             acc.push(InlayHint {
58                 range: pat.syntax().text_range(),
59                 kind: InlayKind::BindingModeHint,
60                 label: bm.to_string().into(),
61                 tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
62             });
63         }
64         ast::Pat::OrPat(pat) if outer_paren_pat.is_none() => {
65             acc.push(InlayHint {
66                 range: pat.syntax().text_range(),
67                 kind: InlayKind::OpeningParenthesis,
68                 label: "(".into(),
69                 tooltip: None,
70             });
71             acc.push(InlayHint {
72                 range: pat.syntax().text_range(),
73                 kind: InlayKind::ClosingParenthesis,
74                 label: ")".into(),
75                 tooltip: None,
76             });
77         }
78         _ => (),
79     }
80
81     Some(())
82 }
83
84 #[cfg(test)]
85 mod tests {
86     use crate::{
87         inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
88         InlayHintsConfig,
89     };
90
91     #[test]
92     fn hints_binding_modes() {
93         check_with_config(
94             InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
95             r#"
96 fn __(
97     (x,): (u32,),
98     (x,): &(u32,),
99   //^^^^&
100    //^ ref
101     (x,): &mut (u32,)
102   //^^^^&mut
103    //^ ref mut
104 ) {
105     let (x,) = (0,);
106     let (x,) = &(0,);
107       //^^^^ &
108        //^ ref
109     let (x,) = &mut (0,);
110       //^^^^ &mut
111        //^ ref mut
112     let &mut (x,) = &mut (0,);
113     let (ref mut x,) = &mut (0,);
114       //^^^^^^^^^^^^ &mut
115     let &mut (ref mut x,) = &mut (0,);
116     let (mut x,) = &mut (0,);
117       //^^^^^^^^ &mut
118     match (0,) {
119         (x,) => ()
120     }
121     match &(0,) {
122         (x,) | (x,) => (),
123       //^^^^^^^^^^^&
124        //^ ref
125               //^ ref
126       //^^^^^^^^^^^(
127       //^^^^^^^^^^^)
128         ((x,) | (x,)) => (),
129       //^^^^^^^^^^^^^&
130         //^ ref
131                //^ ref
132     }
133     match &mut (0,) {
134         (x,) => ()
135       //^^^^ &mut
136        //^ ref mut
137     }
138 }"#,
139         );
140     }
141 }