diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-12 21:18:14 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-12 21:18:14 +0000 |
commit | eb931c0d9e0877e573622253ae5b05563841037b (patch) | |
tree | 653ef81450a4d39c5b46f98c97c23fa8586dd7f8 /crates/ra_ide_api | |
parent | e56072bfa3e5af69a4c293a38de6e1350ada3573 (diff) | |
parent | 1ed7fbfc1badd2c2a42b4dc2feb1b4bf7835d3ef (diff) |
Merge #505
505: Inherent methods r=matklad a=flodiebold
This adds resolution, type checking and completion for inherent methods.
The main open question here is the caching, I think. I'm not sure whether we should be caching method resolutions in a more fine grained way (currently we just build a hash map of types -> impl blocks, and iterate through all potential impl blocks when looking for a method).
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_dot.rs | 59 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/completion_item.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide_api/src/db.rs | 1 |
3 files changed, 64 insertions, 5 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 80d0b1663..37985b398 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs | |||
@@ -17,8 +17,9 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Ca | |||
17 | }; | 17 | }; |
18 | let receiver_ty = infer_result[expr].clone(); | 18 | let receiver_ty = infer_result[expr].clone(); |
19 | if !ctx.is_call { | 19 | if !ctx.is_call { |
20 | complete_fields(acc, ctx, receiver_ty)?; | 20 | complete_fields(acc, ctx, receiver_ty.clone())?; |
21 | } | 21 | } |
22 | complete_methods(acc, ctx, receiver_ty)?; | ||
22 | Ok(()) | 23 | Ok(()) |
23 | } | 24 | } |
24 | 25 | ||
@@ -55,6 +56,24 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) | |||
55 | Ok(()) | 56 | Ok(()) |
56 | } | 57 | } |
57 | 58 | ||
59 | fn complete_methods( | ||
60 | acc: &mut Completions, | ||
61 | ctx: &CompletionContext, | ||
62 | receiver: Ty, | ||
63 | ) -> Cancelable<()> { | ||
64 | receiver.iterate_methods(ctx.db, |func| { | ||
65 | let sig = func.signature(ctx.db); | ||
66 | if sig.has_self_param() { | ||
67 | CompletionItem::new(CompletionKind::Reference, sig.name().to_string()) | ||
68 | .from_function(ctx, func) | ||
69 | .kind(CompletionItemKind::Method) | ||
70 | .add_to(acc); | ||
71 | } | ||
72 | Ok(None::<()>) | ||
73 | })?; | ||
74 | Ok(()) | ||
75 | } | ||
76 | |||
58 | #[cfg(test)] | 77 | #[cfg(test)] |
59 | mod tests { | 78 | mod tests { |
60 | use crate::completion::*; | 79 | use crate::completion::*; |
@@ -87,7 +106,8 @@ mod tests { | |||
87 | } | 106 | } |
88 | } | 107 | } |
89 | ", | 108 | ", |
90 | r#"the_field "(u32,)""#, | 109 | r#"the_field "(u32,)" |
110 | foo "foo($0)""#, | ||
91 | ); | 111 | ); |
92 | } | 112 | } |
93 | 113 | ||
@@ -102,7 +122,8 @@ mod tests { | |||
102 | } | 122 | } |
103 | } | 123 | } |
104 | ", | 124 | ", |
105 | r#"the_field "(u32, i32)""#, | 125 | r#"the_field "(u32, i32)" |
126 | foo "foo($0)""#, | ||
106 | ); | 127 | ); |
107 | } | 128 | } |
108 | 129 | ||
@@ -118,4 +139,36 @@ mod tests { | |||
118 | r#""#, | 139 | r#""#, |
119 | ); | 140 | ); |
120 | } | 141 | } |
142 | |||
143 | #[test] | ||
144 | fn test_method_completion() { | ||
145 | check_ref_completion( | ||
146 | r" | ||
147 | struct A {} | ||
148 | impl A { | ||
149 | fn the_method(&self) {} | ||
150 | } | ||
151 | fn foo(a: A) { | ||
152 | a.<|> | ||
153 | } | ||
154 | ", | ||
155 | r#"the_method "the_method($0)""#, | ||
156 | ); | ||
157 | } | ||
158 | |||
159 | #[test] | ||
160 | fn test_no_non_self_method() { | ||
161 | check_ref_completion( | ||
162 | r" | ||
163 | struct A {} | ||
164 | impl A { | ||
165 | fn the_method() {} | ||
166 | } | ||
167 | fn foo(a: A) { | ||
168 | a.<|> | ||
169 | } | ||
170 | ", | ||
171 | r#""#, | ||
172 | ); | ||
173 | } | ||
121 | } | 174 | } |
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index e7fa967a0..b75d65de3 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs | |||
@@ -37,6 +37,7 @@ pub enum CompletionItemKind { | |||
37 | Const, | 37 | Const, |
38 | Trait, | 38 | Trait, |
39 | TypeAlias, | 39 | TypeAlias, |
40 | Method, | ||
40 | } | 41 | } |
41 | 42 | ||
42 | #[derive(Debug, PartialEq, Eq)] | 43 | #[derive(Debug, PartialEq, Eq)] |
@@ -183,10 +184,14 @@ impl Builder { | |||
183 | self | 184 | self |
184 | } | 185 | } |
185 | 186 | ||
186 | fn from_function(mut self, ctx: &CompletionContext, function: hir::Function) -> Builder { | 187 | pub(super) fn from_function( |
188 | mut self, | ||
189 | ctx: &CompletionContext, | ||
190 | function: hir::Function, | ||
191 | ) -> Builder { | ||
187 | // If not an import, add parenthesis automatically. | 192 | // If not an import, add parenthesis automatically. |
188 | if ctx.use_item_syntax.is_none() && !ctx.is_call { | 193 | if ctx.use_item_syntax.is_none() && !ctx.is_call { |
189 | if function.signature(ctx.db).args().is_empty() { | 194 | if function.signature(ctx.db).params().is_empty() { |
190 | self.snippet = Some(format!("{}()$0", self.label)); | 195 | self.snippet = Some(format!("{}()$0", self.label)); |
191 | } else { | 196 | } else { |
192 | self.snippet = Some(format!("{}($0)", self.label)); | 197 | self.snippet = Some(format!("{}($0)", self.label)); |
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs index efdf261be..60f84675d 100644 --- a/crates/ra_ide_api/src/db.rs +++ b/crates/ra_ide_api/src/db.rs | |||
@@ -124,6 +124,7 @@ salsa::database_storage! { | |||
124 | fn enum_data() for hir::db::EnumDataQuery; | 124 | fn enum_data() for hir::db::EnumDataQuery; |
125 | fn enum_variant_data() for hir::db::EnumVariantDataQuery; | 125 | fn enum_variant_data() for hir::db::EnumVariantDataQuery; |
126 | fn impls_in_module() for hir::db::ImplsInModuleQuery; | 126 | fn impls_in_module() for hir::db::ImplsInModuleQuery; |
127 | fn impls_in_crate() for hir::db::ImplsInCrateQuery; | ||
127 | fn body_hir() for hir::db::BodyHirQuery; | 128 | fn body_hir() for hir::db::BodyHirQuery; |
128 | fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery; | 129 | fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery; |
129 | fn fn_signature() for hir::db::FnSignatureQuery; | 130 | fn fn_signature() for hir::db::FnSignatureQuery; |