aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-12 21:18:14 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-12 21:18:14 +0000
commiteb931c0d9e0877e573622253ae5b05563841037b (patch)
tree653ef81450a4d39c5b46f98c97c23fa8586dd7f8 /crates/ra_ide_api
parente56072bfa3e5af69a4c293a38de6e1350ada3573 (diff)
parent1ed7fbfc1badd2c2a42b4dc2feb1b4bf7835d3ef (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.rs59
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs9
-rw-r--r--crates/ra_ide_api/src/db.rs1
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
59fn 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)]
59mod tests { 78mod 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;