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