aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/complete_dot.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/complete_dot.rs')
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs124
1 files changed, 121 insertions, 3 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index f433faef3..b5448af5c 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{HasVisibility, Type}; 3use hir::{HasVisibility, HirDisplay, Type};
4 4
5use crate::completion::completion_item::CompletionKind; 5use crate::completion::completion_item::CompletionKind;
6use crate::{ 6use crate::{
@@ -8,6 +8,7 @@ use crate::{
8 CompletionItem, 8 CompletionItem,
9}; 9};
10use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
11use std::cmp::Ordering;
11 12
12/// Complete dot accesses, i.e. fields or methods (and .await syntax). 13/// Complete dot accesses, i.e. fields or methods (and .await syntax).
13pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 14pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
@@ -37,7 +38,31 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
37 38
38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 39fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
39 for receiver in receiver.autoderef(ctx.db) { 40 for receiver in receiver.autoderef(ctx.db) {
40 for (field, ty) in receiver.fields(ctx.db) { 41 let mut fields = receiver.fields(ctx.db);
42 if let Some(call_info) = &ctx.call_info {
43 if let Some(active_parameter_type) = call_info.active_parameter_type() {
44 let active_parameter_name = call_info.active_parameter_name().unwrap();
45 fields.sort_by(|a, b| {
46 // For the same type
47 if active_parameter_type == a.1.display(ctx.db).to_string() {
48 // If same type + same name then go top position
49 if active_parameter_name == a.0.name(ctx.db).to_string() {
50 Ordering::Less
51 } else {
52 if active_parameter_type == b.1.display(ctx.db).to_string() {
53 Ordering::Equal
54 } else {
55 Ordering::Less
56 }
57 }
58 } else {
59 Ordering::Greater
60 }
61 });
62 }
63 }
64
65 for (field, ty) in fields {
41 if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { 66 if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
42 // Skip private field. FIXME: If the definition location of the 67 // Skip private field. FIXME: If the definition location of the
43 // field is editable, we should show the completion 68 // field is editable, we should show the completion
@@ -70,13 +95,20 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
70 95
71#[cfg(test)] 96#[cfg(test)]
72mod tests { 97mod tests {
73 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 98 use crate::completion::{
99 test_utils::{do_completion, do_completion_without_sort},
100 CompletionItem, CompletionKind,
101 };
74 use insta::assert_debug_snapshot; 102 use insta::assert_debug_snapshot;
75 103
76 fn do_ref_completion(code: &str) -> Vec<CompletionItem> { 104 fn do_ref_completion(code: &str) -> Vec<CompletionItem> {
77 do_completion(code, CompletionKind::Reference) 105 do_completion(code, CompletionKind::Reference)
78 } 106 }
79 107
108 fn do_ref_completion_without_sort(code: &str) -> Vec<CompletionItem> {
109 do_completion_without_sort(code, CompletionKind::Reference)
110 }
111
80 #[test] 112 #[test]
81 fn test_struct_field_completion() { 113 fn test_struct_field_completion() {
82 assert_debug_snapshot!( 114 assert_debug_snapshot!(
@@ -104,6 +136,92 @@ mod tests {
104 } 136 }
105 137
106 #[test] 138 #[test]
139 fn test_struct_field_completion_in_func_call() {
140 assert_debug_snapshot!(
141 do_ref_completion_without_sort(
142 r"
143 struct A { another_field: i64, the_field: u32, my_string: String }
144 fn test(my_param: u32) -> u32 { my_param }
145 fn foo(a: A) {
146 test(a.<|>)
147 }
148 ",
149 ),
150 @r###"
151 [
152 CompletionItem {
153 label: "the_field",
154 source_range: [201; 201),
155 delete: [201; 201),
156 insert: "the_field",
157 kind: Field,
158 detail: "u32",
159 },
160 CompletionItem {
161 label: "another_field",
162 source_range: [201; 201),
163 delete: [201; 201),
164 insert: "another_field",
165 kind: Field,
166 detail: "i64",
167 },
168 CompletionItem {
169 label: "my_string",
170 source_range: [201; 201),
171 delete: [201; 201),
172 insert: "my_string",
173 kind: Field,
174 detail: "{unknown}",
175 },
176 ]
177 "###
178 );
179 }
180
181 #[test]
182 fn test_struct_field_completion_in_func_call_with_type_and_name() {
183 assert_debug_snapshot!(
184 do_ref_completion_without_sort(
185 r"
186 struct A { another_field: i64, another_good_type: u32, the_field: u32 }
187 fn test(the_field: u32) -> u32 { the_field }
188 fn foo(a: A) {
189 test(a.<|>)
190 }
191 ",
192 ),
193 @r###"
194 [
195 CompletionItem {
196 label: "the_field",
197 source_range: [208; 208),
198 delete: [208; 208),
199 insert: "the_field",
200 kind: Field,
201 detail: "u32",
202 },
203 CompletionItem {
204 label: "another_good_type",
205 source_range: [208; 208),
206 delete: [208; 208),
207 insert: "another_good_type",
208 kind: Field,
209 detail: "u32",
210 },
211 CompletionItem {
212 label: "another_field",
213 source_range: [208; 208),
214 delete: [208; 208),
215 insert: "another_field",
216 kind: Field,
217 detail: "i64",
218 },
219 ]
220 "###
221 );
222 }
223
224 #[test]
107 fn test_struct_field_completion_self() { 225 fn test_struct_field_completion_self() {
108 assert_debug_snapshot!( 226 assert_debug_snapshot!(
109 do_ref_completion( 227 do_ref_completion(