]> git.lizzy.rs Git - rust.git/blob - crates/ra_ide_api/src/completion/presentation.rs
simplify
[rust.git] / crates / ra_ide_api / src / completion / presentation.rs
1 //! This modules takes care of rendering various defenitions as completion items.
2 use test_utils::tested_by;
3 use hir::Docs;
4
5 use crate::completion::{
6     Completions, CompletionKind, CompletionItemKind, CompletionContext, CompletionItem,
7     function_label,
8 };
9
10 impl Completions {
11     pub(crate) fn add_field(
12         &mut self,
13         ctx: &CompletionContext,
14         field: hir::StructField,
15         substs: &hir::Substs,
16     ) {
17         CompletionItem::new(
18             CompletionKind::Reference,
19             ctx.source_range(),
20             field.name(ctx.db).to_string(),
21         )
22         .kind(CompletionItemKind::Field)
23         .detail(field.ty(ctx.db).subst(substs).to_string())
24         .set_documentation(field.docs(ctx.db))
25         .add_to(self);
26     }
27
28     pub(crate) fn add_pos_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
29         CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
30             .kind(CompletionItemKind::Field)
31             .detail(ty.to_string())
32             .add_to(self);
33     }
34
35     pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) {
36         let sig = func.signature(ctx.db);
37
38         let mut builder = CompletionItem::new(
39             CompletionKind::Reference,
40             ctx.source_range(),
41             sig.name().to_string(),
42         )
43         .kind(if sig.has_self_param() {
44             CompletionItemKind::Method
45         } else {
46             CompletionItemKind::Function
47         })
48         .set_documentation(func.docs(ctx.db))
49         .set_detail(function_item_label(ctx, func));
50         // If not an import, add parenthesis automatically.
51         if ctx.use_item_syntax.is_none() && !ctx.is_call {
52             tested_by!(inserts_parens_for_function_calls);
53             let snippet =
54                 if sig.params().is_empty() || sig.has_self_param() && sig.params().len() == 1 {
55                     format!("{}()$0", sig.name())
56                 } else {
57                     format!("{}($0)", sig.name())
58                 };
59             builder = builder.insert_snippet(snippet);
60         }
61         self.add(builder)
62     }
63 }
64
65 fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
66     let node = function.source(ctx.db).1;
67     function_label(&node)
68 }
69
70 #[cfg(test)]
71 mod tests {
72     use test_utils::covers;
73
74     use crate::completion::{CompletionKind, completion_item::check_completion};
75
76     fn check_reference_completion(code: &str, expected_completions: &str) {
77         check_completion(code, expected_completions, CompletionKind::Reference);
78     }
79
80     #[test]
81     fn inserts_parens_for_function_calls() {
82         covers!(inserts_parens_for_function_calls);
83         check_reference_completion(
84             "inserts_parens_for_function_calls1",
85             r"
86             fn no_args() {}
87             fn main() { no_<|> }
88             ",
89         );
90         check_reference_completion(
91             "inserts_parens_for_function_calls2",
92             r"
93             fn with_args(x: i32, y: String) {}
94             fn main() { with_<|> }
95             ",
96         );
97         check_reference_completion(
98             "inserts_parens_for_function_calls3",
99             r"
100             struct S {}
101             impl S {
102                 fn foo(&self) {}
103             }
104             fn bar(s: &S) {
105                 s.f<|>
106             }
107             ",
108         )
109     }
110
111     #[test]
112     fn dont_render_function_parens_in_use_item() {
113         check_reference_completion(
114             "dont_render_function_parens_in_use_item",
115             "
116             //- /lib.rs
117             mod m { pub fn foo() {} }
118             use crate::m::f<|>;
119             ",
120         )
121     }
122
123     #[test]
124     fn dont_render_function_parens_if_already_call() {
125         check_reference_completion(
126             "dont_render_function_parens_if_already_call",
127             "
128             //- /lib.rs
129             fn frobnicate() {}
130             fn main() {
131                 frob<|>();
132             }
133             ",
134         );
135         check_reference_completion(
136             "dont_render_function_parens_if_already_call_assoc_fn",
137             "
138             //- /lib.rs
139             struct Foo {}
140             impl Foo { fn new() -> Foo {} }
141             fn main() {
142                 Foo::ne<|>();
143             }
144             ",
145         )
146     }
147
148 }