aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/inlay_hints.rs
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2019-07-19 22:20:09 +0100
committerKirill Bulatov <[email protected]>2019-07-20 21:45:26 +0100
commit201b344f2b0c9e84606115d135cd658d0a955d2c (patch)
tree1dc9c308c71ea4d2512d351de12933c6475abba8 /crates/ra_ide_api/src/inlay_hints.rs
parent761fc71083b9d810aa006210d6df2b0edf95cf33 (diff)
Refactor server api
Diffstat (limited to 'crates/ra_ide_api/src/inlay_hints.rs')
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
new file mode 100644
index 000000000..4d1df65d0
--- /dev/null
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -0,0 +1,110 @@
1use ra_syntax::{
2 algo::visit::{visitor, Visitor},
3 ast::{self, PatKind, TypeAscriptionOwner},
4 AstNode, SmolStr, SourceFile, SyntaxNode, TextRange,
5};
6
7#[derive(Debug, PartialEq, Eq)]
8pub enum InlayKind {
9 LetBinding,
10 ClosureParameter,
11}
12
13#[derive(Debug)]
14pub struct InlayHint {
15 pub range: TextRange,
16 pub text: SmolStr,
17 pub inlay_kind: InlayKind,
18}
19
20pub(crate) fn inlay_hints(file: &SourceFile) -> Vec<InlayHint> {
21 file.syntax().descendants().map(|node| get_inlay_hints(&node)).flatten().collect()
22}
23
24fn get_inlay_hints(node: &SyntaxNode) -> Vec<InlayHint> {
25 visitor()
26 .visit(|let_statement: ast::LetStmt| {
27 let let_syntax = let_statement.syntax();
28
29 if let_statement.ascribed_type().is_some() {
30 return Vec::new();
31 }
32
33 let pat_range = match let_statement.pat().map(|pat| pat.kind()) {
34 Some(PatKind::BindPat(bind_pat)) => bind_pat.syntax().text_range(),
35 Some(PatKind::TuplePat(tuple_pat)) => tuple_pat.syntax().text_range(),
36 _ => return Vec::new(),
37 };
38
39 vec![InlayHint {
40 range: pat_range,
41 text: let_syntax.text().to_smol_string(),
42 inlay_kind: InlayKind::LetBinding,
43 }]
44 })
45 .visit(|closure_parameter: ast::LambdaExpr| {
46 if let Some(param_list) = closure_parameter.param_list() {
47 param_list
48 .params()
49 .filter(|closure_param| closure_param.ascribed_type().is_none())
50 .map(|closure_param| {
51 let closure_param_syntax = closure_param.syntax();
52 InlayHint {
53 range: closure_param_syntax.text_range(),
54 text: closure_param_syntax.text().to_smol_string(),
55 inlay_kind: InlayKind::ClosureParameter,
56 }
57 })
58 .collect()
59 } else {
60 Vec::new()
61 }
62 })
63 .accept(&node)
64 .unwrap_or_else(Vec::new)
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use insta::assert_debug_snapshot_matches;
71
72 #[test]
73 fn test_inlay_hints() {
74 let file = SourceFile::parse(
75 r#"
76struct OuterStruct {}
77
78fn main() {
79 struct InnerStruct {}
80
81 let test = 54;
82 let test = InnerStruct {};
83 let test = OuterStruct {};
84 let test = vec![222];
85 let mut test = Vec::new();
86 test.push(333);
87 let test = test.into_iter().map(|i| i * i).collect::<Vec<_>>();
88 let mut test = 33;
89 let _ = 22;
90 let test: Vec<_> = (0..3).collect();
91
92 let _ = (0..23).map(|i: u32| {
93 let i_squared = i * i;
94 i_squared
95 });
96
97 let test: i32 = 33;
98
99 let (x, c) = (42, 'a');
100 let test = (42, 'a');
101}
102
103"#,
104 )
105 .ok()
106 .unwrap();
107 let hints = inlay_hints(&file);
108 assert_debug_snapshot_matches!("inlay_hints", hints);
109 }
110}