aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/inlay_hints.rs
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2019-07-21 21:28:05 +0100
committerKirill Bulatov <[email protected]>2019-07-21 21:44:37 +0100
commit09c7c86696eb8289c9a8ab30bdbb824824c51eb1 (patch)
treed72cc0adb850d0d20774b3b2cffa148f686bc964 /crates/ra_ide_api/src/inlay_hints.rs
parent24784c60df583d1807faa889a84312df1d2e3b22 (diff)
Resolve types on the server
Diffstat (limited to 'crates/ra_ide_api/src/inlay_hints.rs')
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs126
1 files changed, 73 insertions, 53 deletions
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
index 739a44b19..7d49ebcf4 100644
--- a/crates/ra_ide_api/src/inlay_hints.rs
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -1,3 +1,6 @@
1use crate::{db::RootDatabase, FileId};
2use hir::{HirDisplay, Ty};
3use ra_syntax::ast::Pat;
1use ra_syntax::{ 4use ra_syntax::{
2 algo::visit::{visitor, Visitor}, 5 algo::visit::{visitor, Visitor},
3 ast::{self, PatKind, TypeAscriptionOwner}, 6 ast::{self, PatKind, TypeAscriptionOwner},
@@ -15,63 +18,101 @@ pub struct InlayHint {
15 pub range: TextRange, 18 pub range: TextRange,
16 pub text: SmolStr, 19 pub text: SmolStr,
17 pub inlay_kind: InlayKind, 20 pub inlay_kind: InlayKind,
21 pub inlay_type_string: String,
18} 22}
19 23
20pub(crate) fn inlay_hints(file: &SourceFile) -> Vec<InlayHint> { 24pub(crate) fn inlay_hints(db: &RootDatabase, file_id: FileId, file: &SourceFile) -> Vec<InlayHint> {
21 file.syntax().descendants().map(|node| get_inlay_hints(&node)).flatten().collect() 25 file.syntax()
26 .descendants()
27 .map(|node| get_inlay_hints(db, file_id, &node).unwrap_or_default())
28 .flatten()
29 .collect()
22} 30}
23 31
24fn get_inlay_hints(node: &SyntaxNode) -> Vec<InlayHint> { 32fn get_inlay_hints(
33 db: &RootDatabase,
34 file_id: FileId,
35 node: &SyntaxNode,
36) -> Option<Vec<InlayHint>> {
25 visitor() 37 visitor()
26 .visit(|let_statement: ast::LetStmt| { 38 .visit(|let_statement: ast::LetStmt| {
27 let let_syntax = let_statement.syntax(); 39 let let_syntax = let_statement.syntax();
28 40
29 if let_statement.ascribed_type().is_some() { 41 if let_statement.ascribed_type().is_some() {
30 return Vec::new(); 42 return None;
31 } 43 }
32 44
33 let pat_range = match let_statement.pat().map(|pat| pat.kind()) { 45 let let_pat = let_statement.pat()?;
34 Some(PatKind::BindPat(bind_pat)) => bind_pat.syntax().text_range(), 46 let inlay_type_string = get_node_displayable_type(db, file_id, let_syntax, &let_pat)?
35 Some(PatKind::TuplePat(tuple_pat)) => tuple_pat.syntax().text_range(), 47 .display(db)
36 _ => return Vec::new(), 48 .to_string();;
49
50 let pat_range = match let_pat.kind() {
51 PatKind::BindPat(bind_pat) => bind_pat.syntax().text_range(),
52 PatKind::TuplePat(tuple_pat) => tuple_pat.syntax().text_range(),
53 _ => return None,
37 }; 54 };
38 55
39 vec![InlayHint { 56 Some(vec![InlayHint {
40 range: pat_range, 57 range: pat_range,
41 text: let_syntax.text().to_smol_string(), 58 text: let_syntax.text().to_smol_string(),
42 inlay_kind: InlayKind::LetBinding, 59 inlay_kind: InlayKind::LetBinding,
43 }] 60 inlay_type_string,
61 }])
44 }) 62 })
45 .visit(|closure_parameter: ast::LambdaExpr| { 63 .visit(|closure_parameter: ast::LambdaExpr| match closure_parameter.param_list() {
46 if let Some(param_list) = closure_parameter.param_list() { 64 Some(param_list) => Some(
47 param_list 65 param_list
48 .params() 66 .params()
49 .filter(|closure_param| closure_param.ascribed_type().is_none()) 67 .filter(|closure_param| closure_param.ascribed_type().is_none())
50 .map(|closure_param| { 68 .filter_map(|closure_param| {
51 let closure_param_syntax = closure_param.syntax(); 69 let closure_param_syntax = closure_param.syntax();
52 InlayHint { 70 let inlay_type_string = get_node_displayable_type(
71 db,
72 file_id,
73 closure_param_syntax,
74 &closure_param.pat()?,
75 )?
76 .display(db)
77 .to_string();
78 Some(InlayHint {
53 range: closure_param_syntax.text_range(), 79 range: closure_param_syntax.text_range(),
54 text: closure_param_syntax.text().to_smol_string(), 80 text: closure_param_syntax.text().to_smol_string(),
55 inlay_kind: InlayKind::ClosureParameter, 81 inlay_kind: InlayKind::ClosureParameter,
56 } 82 inlay_type_string,
83 })
57 }) 84 })
58 .collect() 85 .collect(),
59 } else { 86 ),
60 Vec::new() 87 None => None,
61 }
62 }) 88 })
63 .accept(&node) 89 .accept(&node)?
64 .unwrap_or_default() 90}
91
92fn get_node_displayable_type(
93 db: &RootDatabase,
94 file_id: FileId,
95 node_syntax: &SyntaxNode,
96 node_pat: &Pat,
97) -> Option<Ty> {
98 let analyzer = hir::SourceAnalyzer::new(db, file_id, node_syntax, None);
99 analyzer.type_of_pat(db, node_pat).and_then(|resolved_type| {
100 if let Ty::Apply(_) = resolved_type {
101 Some(resolved_type)
102 } else {
103 None
104 }
105 })
65} 106}
66 107
67#[cfg(test)] 108#[cfg(test)]
68mod tests { 109mod tests {
69 use super::*; 110 use crate::mock_analysis::single_file;
70 use insta::assert_debug_snapshot_matches; 111 use insta::assert_debug_snapshot_matches;
71 112
72 #[test] 113 #[test]
73 fn test_inlay_hints() { 114 fn test_inlay_hints() {
74 let file = SourceFile::parse( 115 let (analysis, file_id) = single_file(
75 r#" 116 r#"
76struct OuterStruct {} 117struct OuterStruct {}
77 118
@@ -99,66 +140,45 @@ fn main() {
99 let (x, c) = (42, 'a'); 140 let (x, c) = (42, 'a');
100 let test = (42, 'a'); 141 let test = (42, 'a');
101} 142}
102
103"#, 143"#,
104 ) 144 );
105 .ok() 145
106 .unwrap(); 146 assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[
107 assert_debug_snapshot_matches!(inlay_hints(&file), @r#"[
108 InlayHint { 147 InlayHint {
109 range: [71; 75), 148 range: [71; 75),
110 text: "let test = 54;", 149 text: "let test = 54;",
111 inlay_kind: LetBinding, 150 inlay_kind: LetBinding,
112 }, 151 inlay_type_string: "i32",
113 InlayHint {
114 range: [90; 94),
115 text: "let test = InnerStruct {};",
116 inlay_kind: LetBinding,
117 }, 152 },
118 InlayHint { 153 InlayHint {
119 range: [121; 125), 154 range: [121; 125),
120 text: "let test = OuterStruct {};", 155 text: "let test = OuterStruct {};",
121 inlay_kind: LetBinding, 156 inlay_kind: LetBinding,
122 }, 157 inlay_type_string: "OuterStruct",
123 InlayHint {
124 range: [152; 156),
125 text: "let test = vec![222];",
126 inlay_kind: LetBinding,
127 },
128 InlayHint {
129 range: [178; 186),
130 text: "let mut test = Vec::new();",
131 inlay_kind: LetBinding,
132 },
133 InlayHint {
134 range: [229; 233),
135 text: "let test = test.into_iter().map(|i| i * i).collect::<Vec<_>>();",
136 inlay_kind: LetBinding,
137 },
138 InlayHint {
139 range: [258; 259),
140 text: "i",
141 inlay_kind: ClosureParameter,
142 }, 158 },
143 InlayHint { 159 InlayHint {
144 range: [297; 305), 160 range: [297; 305),
145 text: "let mut test = 33;", 161 text: "let mut test = 33;",
146 inlay_kind: LetBinding, 162 inlay_kind: LetBinding,
163 inlay_type_string: "i32",
147 }, 164 },
148 InlayHint { 165 InlayHint {
149 range: [417; 426), 166 range: [417; 426),
150 text: "let i_squared = i * i;", 167 text: "let i_squared = i * i;",
151 inlay_kind: LetBinding, 168 inlay_kind: LetBinding,
169 inlay_type_string: "u32",
152 }, 170 },
153 InlayHint { 171 InlayHint {
154 range: [496; 502), 172 range: [496; 502),
155 text: "let (x, c) = (42, \'a\');", 173 text: "let (x, c) = (42, \'a\');",
156 inlay_kind: LetBinding, 174 inlay_kind: LetBinding,
175 inlay_type_string: "(i32, char)",
157 }, 176 },
158 InlayHint { 177 InlayHint {
159 range: [524; 528), 178 range: [524; 528),
160 text: "let test = (42, \'a\');", 179 text: "let test = (42, \'a\');",
161 inlay_kind: LetBinding, 180 inlay_kind: LetBinding,
181 inlay_type_string: "(i32, char)",
162 }, 182 },
163]"# 183]"#
164 ); 184 );