diff options
Diffstat (limited to 'crates/ra_ide_api/src')
7 files changed, 209 insertions, 9 deletions
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 98060947a..5cf55a496 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! This modules takes care of rendering various defenitions as completion items. | 1 | //! This modules takes care of rendering various defenitions as completion items. |
2 | use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution}; | 2 | use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty}; |
3 | use join_to_string::join; | 3 | use join_to_string::join; |
4 | use ra_syntax::ast::NameOwner; | 4 | use ra_syntax::ast::NameOwner; |
5 | use test_utils::tested_by; | 5 | use test_utils::tested_by; |
@@ -80,10 +80,18 @@ impl Completions { | |||
80 | None, | 80 | None, |
81 | ), | 81 | ), |
82 | }; | 82 | }; |
83 | CompletionItem::new(completion_kind, ctx.source_range(), local_name) | 83 | |
84 | .kind(kind) | 84 | let mut completion_item = |
85 | .set_documentation(docs) | 85 | CompletionItem::new(completion_kind, ctx.source_range(), local_name); |
86 | .add_to(self) | 86 | if let Resolution::LocalBinding(pat_id) = def { |
87 | let ty = ctx | ||
88 | .analyzer | ||
89 | .type_of_pat_by_id(ctx.db, pat_id.clone()) | ||
90 | .filter(|t| t != &Ty::Unknown) | ||
91 | .map(|t| t.display(ctx.db).to_string()); | ||
92 | completion_item = completion_item.set_detail(ty); | ||
93 | }; | ||
94 | completion_item.kind(kind).set_documentation(docs).add_to(self) | ||
87 | } | 95 | } |
88 | 96 | ||
89 | pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) { | 97 | pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) { |
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_if_let.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_if_let.snap index 2a22201ad..f94477b43 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_if_let.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_if_let.snap | |||
@@ -1,5 +1,5 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-05-23T22:23:35.122168608Z" | 2 | created: "2019-07-23T16:11:48.828805910Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | 4 | source: crates/ra_ide_api/src/completion/completion_item.rs |
5 | expression: kind_completions | 5 | expression: kind_completions |
@@ -18,6 +18,7 @@ expression: kind_completions | |||
18 | delete: [214; 214), | 18 | delete: [214; 214), |
19 | insert: "b", | 19 | insert: "b", |
20 | kind: Binding, | 20 | kind: Binding, |
21 | detail: "i32", | ||
21 | }, | 22 | }, |
22 | CompletionItem { | 23 | CompletionItem { |
23 | label: "quux", | 24 | label: "quux", |
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_let.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_let.snap index b9a5dc9c8..590e2a820 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_let.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__bindings_from_let.snap | |||
@@ -1,5 +1,5 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-05-23T22:23:35.122797188Z" | 2 | created: "2019-07-23T16:11:48.828811567Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | 4 | source: crates/ra_ide_api/src/completion/completion_item.rs |
5 | expression: kind_completions | 5 | expression: kind_completions |
@@ -19,6 +19,7 @@ expression: kind_completions | |||
19 | delete: [79; 79), | 19 | delete: [79; 79), |
20 | insert: "x", | 20 | insert: "x", |
21 | kind: Binding, | 21 | kind: Binding, |
22 | detail: "i32", | ||
22 | }, | 23 | }, |
23 | CompletionItem { | 24 | CompletionItem { |
24 | label: "y", | 25 | label: "y", |
@@ -26,5 +27,6 @@ expression: kind_completions | |||
26 | delete: [79; 79), | 27 | delete: [79; 79), |
27 | insert: "y", | 28 | insert: "y", |
28 | kind: Binding, | 29 | kind: Binding, |
30 | detail: "i32", | ||
29 | }, | 31 | }, |
30 | ] | 32 | ] |
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap index 57434210d..158a2e5b9 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap | |||
@@ -1,5 +1,5 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-05-23T22:23:35.142044205Z" | 2 | created: "2019-07-23T16:11:48.860949870Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | 4 | source: crates/ra_ide_api/src/completion/completion_item.rs |
5 | expression: kind_completions | 5 | expression: kind_completions |
@@ -11,6 +11,7 @@ expression: kind_completions | |||
11 | delete: [126; 126), | 11 | delete: [126; 126), |
12 | insert: "bar", | 12 | insert: "bar", |
13 | kind: Binding, | 13 | kind: Binding, |
14 | detail: "i32", | ||
14 | }, | 15 | }, |
15 | CompletionItem { | 16 | CompletionItem { |
16 | label: "foo", | 17 | label: "foo", |
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap index e1af94870..b7bcbe864 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap | |||
@@ -1,5 +1,5 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-05-23T22:23:35.141900902Z" | 2 | created: "2019-07-23T16:11:48.859812318Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | 4 | source: crates/ra_ide_api/src/completion/completion_item.rs |
5 | expression: kind_completions | 5 | expression: kind_completions |
@@ -18,5 +18,6 @@ expression: kind_completions | |||
18 | delete: [25; 25), | 18 | delete: [25; 25), |
19 | insert: "self", | 19 | insert: "self", |
20 | kind: Binding, | 20 | kind: Binding, |
21 | detail: "&{unknown}", | ||
21 | }, | 22 | }, |
22 | ] | 23 | ] |
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..174662beb --- /dev/null +++ b/crates/ra_ide_api/src/inlay_hints.rs | |||
@@ -0,0 +1,180 @@ | |||
1 | use crate::{db::RootDatabase, FileId}; | ||
2 | use hir::{HirDisplay, Ty}; | ||
3 | use ra_syntax::ast::Pat; | ||
4 | use ra_syntax::{ | ||
5 | algo::visit::{visitor, Visitor}, | ||
6 | ast::{self, PatKind, TypeAscriptionOwner}, | ||
7 | AstNode, SmolStr, SourceFile, SyntaxNode, TextRange, | ||
8 | }; | ||
9 | |||
10 | #[derive(Debug, PartialEq, Eq)] | ||
11 | pub enum InlayKind { | ||
12 | LetBindingType, | ||
13 | ClosureParameterType, | ||
14 | } | ||
15 | |||
16 | #[derive(Debug)] | ||
17 | pub struct InlayHint { | ||
18 | pub range: TextRange, | ||
19 | pub kind: InlayKind, | ||
20 | pub label: SmolStr, | ||
21 | } | ||
22 | |||
23 | pub(crate) fn inlay_hints(db: &RootDatabase, file_id: FileId, file: &SourceFile) -> Vec<InlayHint> { | ||
24 | file.syntax() | ||
25 | .descendants() | ||
26 | .map(|node| get_inlay_hints(db, file_id, &node).unwrap_or_default()) | ||
27 | .flatten() | ||
28 | .collect() | ||
29 | } | ||
30 | |||
31 | fn get_inlay_hints( | ||
32 | db: &RootDatabase, | ||
33 | file_id: FileId, | ||
34 | node: &SyntaxNode, | ||
35 | ) -> Option<Vec<InlayHint>> { | ||
36 | visitor() | ||
37 | .visit(|let_statement: ast::LetStmt| { | ||
38 | let let_syntax = let_statement.syntax(); | ||
39 | |||
40 | if let_statement.ascribed_type().is_some() { | ||
41 | return None; | ||
42 | } | ||
43 | |||
44 | let let_pat = let_statement.pat()?; | ||
45 | let inlay_type_string = get_node_displayable_type(db, file_id, let_syntax, &let_pat)? | ||
46 | .display(db) | ||
47 | .to_string() | ||
48 | .into(); | ||
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, | ||
54 | }; | ||
55 | |||
56 | Some(vec![InlayHint { | ||
57 | range: pat_range, | ||
58 | kind: InlayKind::LetBindingType, | ||
59 | label: inlay_type_string, | ||
60 | }]) | ||
61 | }) | ||
62 | .visit(|closure_parameter: ast::LambdaExpr| match closure_parameter.param_list() { | ||
63 | Some(param_list) => Some( | ||
64 | param_list | ||
65 | .params() | ||
66 | .filter(|closure_param| closure_param.ascribed_type().is_none()) | ||
67 | .filter_map(|closure_param| { | ||
68 | let closure_param_syntax = closure_param.syntax(); | ||
69 | let inlay_type_string = get_node_displayable_type( | ||
70 | db, | ||
71 | file_id, | ||
72 | closure_param_syntax, | ||
73 | &closure_param.pat()?, | ||
74 | )? | ||
75 | .display(db) | ||
76 | .to_string() | ||
77 | .into(); | ||
78 | |||
79 | Some(InlayHint { | ||
80 | range: closure_param_syntax.text_range(), | ||
81 | kind: InlayKind::ClosureParameterType, | ||
82 | label: inlay_type_string, | ||
83 | }) | ||
84 | }) | ||
85 | .collect(), | ||
86 | ), | ||
87 | None => None, | ||
88 | }) | ||
89 | .accept(&node)? | ||
90 | } | ||
91 | |||
92 | fn 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 | }) | ||
106 | } | ||
107 | |||
108 | #[cfg(test)] | ||
109 | mod tests { | ||
110 | use crate::mock_analysis::single_file; | ||
111 | use insta::assert_debug_snapshot_matches; | ||
112 | |||
113 | #[test] | ||
114 | fn test_inlay_hints() { | ||
115 | let (analysis, file_id) = single_file( | ||
116 | r#" | ||
117 | struct OuterStruct {} | ||
118 | |||
119 | fn main() { | ||
120 | struct InnerStruct {} | ||
121 | |||
122 | let test = 54; | ||
123 | let test = InnerStruct {}; | ||
124 | let test = OuterStruct {}; | ||
125 | let test = vec![222]; | ||
126 | let mut test = Vec::new(); | ||
127 | test.push(333); | ||
128 | let test = test.into_iter().map(|i| i * i).collect::<Vec<_>>(); | ||
129 | let mut test = 33; | ||
130 | let _ = 22; | ||
131 | let test: Vec<_> = (0..3).collect(); | ||
132 | |||
133 | let _ = (0..23).map(|i: u32| { | ||
134 | let i_squared = i * i; | ||
135 | i_squared | ||
136 | }); | ||
137 | |||
138 | let test: i32 = 33; | ||
139 | |||
140 | let (x, c) = (42, 'a'); | ||
141 | let test = (42, 'a'); | ||
142 | } | ||
143 | "#, | ||
144 | ); | ||
145 | |||
146 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ | ||
147 | InlayHint { | ||
148 | range: [71; 75), | ||
149 | kind: LetBindingType, | ||
150 | label: "i32", | ||
151 | }, | ||
152 | InlayHint { | ||
153 | range: [121; 125), | ||
154 | kind: LetBindingType, | ||
155 | label: "OuterStruct", | ||
156 | }, | ||
157 | InlayHint { | ||
158 | range: [297; 305), | ||
159 | kind: LetBindingType, | ||
160 | label: "i32", | ||
161 | }, | ||
162 | InlayHint { | ||
163 | range: [417; 426), | ||
164 | kind: LetBindingType, | ||
165 | label: "u32", | ||
166 | }, | ||
167 | InlayHint { | ||
168 | range: [496; 502), | ||
169 | kind: LetBindingType, | ||
170 | label: "(i32, char)", | ||
171 | }, | ||
172 | InlayHint { | ||
173 | range: [524; 528), | ||
174 | kind: LetBindingType, | ||
175 | label: "(i32, char)", | ||
176 | }, | ||
177 | ]"# | ||
178 | ); | ||
179 | } | ||
180 | } | ||
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index c54d574bc..16ffb03ce 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -38,6 +38,7 @@ mod join_lines; | |||
38 | mod typing; | 38 | mod typing; |
39 | mod matching_brace; | 39 | mod matching_brace; |
40 | mod display; | 40 | mod display; |
41 | mod inlay_hints; | ||
41 | 42 | ||
42 | #[cfg(test)] | 43 | #[cfg(test)] |
43 | mod marks; | 44 | mod marks; |
@@ -64,6 +65,7 @@ pub use crate::{ | |||
64 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, | 65 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, |
65 | folding_ranges::{Fold, FoldKind}, | 66 | folding_ranges::{Fold, FoldKind}, |
66 | hover::HoverResult, | 67 | hover::HoverResult, |
68 | inlay_hints::{InlayHint, InlayKind}, | ||
67 | line_index::{LineCol, LineIndex}, | 69 | line_index::{LineCol, LineIndex}, |
68 | line_index_utils::translate_offset_with_edit, | 70 | line_index_utils::translate_offset_with_edit, |
69 | references::ReferenceSearchResult, | 71 | references::ReferenceSearchResult, |
@@ -396,6 +398,11 @@ impl Analysis { | |||
396 | file_structure(&parse.tree()) | 398 | file_structure(&parse.tree()) |
397 | } | 399 | } |
398 | 400 | ||
401 | /// Returns a list of the places in the file where type hints can be displayed. | ||
402 | pub fn inlay_hints(&self, file_id: FileId) -> Cancelable<Vec<InlayHint>> { | ||
403 | self.with_db(|db| inlay_hints::inlay_hints(db, file_id, &db.parse(file_id).tree())) | ||
404 | } | ||
405 | |||
399 | /// Returns the set of folding ranges. | 406 | /// Returns the set of folding ranges. |
400 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { | 407 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { |
401 | let parse = self.db.parse(file_id); | 408 | let parse = self.db.parse(file_id); |