aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/completions.rs')
-rw-r--r--crates/ide_completion/src/completions.rs224
1 files changed, 224 insertions, 0 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
new file mode 100644
index 000000000..3b582ed07
--- /dev/null
+++ b/crates/ide_completion/src/completions.rs
@@ -0,0 +1,224 @@
1//! This module defines an accumulator for completions which are going to be presented to user.
2
3pub(crate) mod attribute;
4pub(crate) mod dot;
5pub(crate) mod record;
6pub(crate) mod pattern;
7pub(crate) mod fn_param;
8pub(crate) mod keyword;
9pub(crate) mod snippet;
10pub(crate) mod qualified_path;
11pub(crate) mod unqualified_path;
12pub(crate) mod postfix;
13pub(crate) mod macro_in_item_position;
14pub(crate) mod trait_impl;
15pub(crate) mod mod_;
16pub(crate) mod flyimport;
17
18use std::iter;
19
20use hir::{known, ModPath, ScopeDef, Type};
21
22use crate::{
23 item::Builder,
24 render::{
25 const_::render_const,
26 enum_variant::render_variant,
27 function::render_fn,
28 macro_::render_macro,
29 pattern::{render_struct_pat, render_variant_pat},
30 render_field, render_resolution, render_tuple_field,
31 type_alias::render_type_alias,
32 RenderContext,
33 },
34 CompletionContext, CompletionItem,
35};
36
37/// Represents an in-progress set of completions being built.
38#[derive(Debug, Default)]
39pub struct Completions {
40 buf: Vec<CompletionItem>,
41}
42
43impl Into<Vec<CompletionItem>> for Completions {
44 fn into(self) -> Vec<CompletionItem> {
45 self.buf
46 }
47}
48
49impl Builder {
50 /// Convenience method, which allows to add a freshly created completion into accumulator
51 /// without binding it to the variable.
52 pub(crate) fn add_to(self, acc: &mut Completions) {
53 acc.add(self.build())
54 }
55}
56
57impl Completions {
58 pub(crate) fn add(&mut self, item: CompletionItem) {
59 self.buf.push(item.into())
60 }
61
62 pub(crate) fn add_all<I>(&mut self, items: I)
63 where
64 I: IntoIterator,
65 I::Item: Into<CompletionItem>,
66 {
67 items.into_iter().for_each(|item| self.add(item.into()))
68 }
69
70 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) {
71 let item = render_field(RenderContext::new(ctx), field, ty);
72 self.add(item);
73 }
74
75 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) {
76 let item = render_tuple_field(RenderContext::new(ctx), field, ty);
77 self.add(item);
78 }
79
80 pub(crate) fn add_resolution(
81 &mut self,
82 ctx: &CompletionContext,
83 local_name: String,
84 resolution: &ScopeDef,
85 ) {
86 if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) {
87 self.add(item);
88 }
89 }
90
91 pub(crate) fn add_macro(
92 &mut self,
93 ctx: &CompletionContext,
94 name: Option<String>,
95 macro_: hir::MacroDef,
96 ) {
97 let name = match name {
98 Some(it) => it,
99 None => return,
100 };
101 if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) {
102 self.add(item);
103 }
104 }
105
106 pub(crate) fn add_function(
107 &mut self,
108 ctx: &CompletionContext,
109 func: hir::Function,
110 local_name: Option<String>,
111 ) {
112 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) {
113 self.add(item)
114 }
115 }
116
117 pub(crate) fn add_variant_pat(
118 &mut self,
119 ctx: &CompletionContext,
120 variant: hir::Variant,
121 local_name: Option<hir::Name>,
122 ) {
123 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name, None) {
124 self.add(item);
125 }
126 }
127
128 pub(crate) fn add_qualified_variant_pat(
129 &mut self,
130 ctx: &CompletionContext,
131 variant: hir::Variant,
132 path: ModPath,
133 ) {
134 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) {
135 self.add(item);
136 }
137 }
138
139 pub(crate) fn add_struct_pat(
140 &mut self,
141 ctx: &CompletionContext,
142 strukt: hir::Struct,
143 local_name: Option<hir::Name>,
144 ) {
145 if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) {
146 self.add(item);
147 }
148 }
149
150 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
151 if let Some(item) = render_const(RenderContext::new(ctx), constant) {
152 self.add(item);
153 }
154 }
155
156 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
157 if let Some(item) = render_type_alias(RenderContext::new(ctx), type_alias) {
158 self.add(item)
159 }
160 }
161
162 pub(crate) fn add_qualified_enum_variant(
163 &mut self,
164 ctx: &CompletionContext,
165 variant: hir::Variant,
166 path: ModPath,
167 ) {
168 let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path));
169 self.add(item);
170 }
171
172 pub(crate) fn add_enum_variant(
173 &mut self,
174 ctx: &CompletionContext,
175 variant: hir::Variant,
176 local_name: Option<String>,
177 ) {
178 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None);
179 self.add(item);
180 }
181}
182
183fn complete_enum_variants(
184 acc: &mut Completions,
185 ctx: &CompletionContext,
186 ty: &hir::Type,
187 cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath),
188) {
189 if let Some(hir::Adt::Enum(enum_data)) =
190 iter::successors(Some(ty.clone()), |ty| ty.remove_ref()).last().and_then(|ty| ty.as_adt())
191 {
192 let variants = enum_data.variants(ctx.db);
193
194 let module = if let Some(module) = ctx.scope.module() {
195 // Compute path from the completion site if available.
196 module
197 } else {
198 // Otherwise fall back to the enum's definition site.
199 enum_data.module(ctx.db)
200 };
201
202 if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
203 if impl_.target_ty(ctx.db) == *ty {
204 for &variant in &variants {
205 let self_path = hir::ModPath::from_segments(
206 hir::PathKind::Plain,
207 iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
208 );
209 cb(acc, ctx, variant, self_path);
210 }
211 }
212 }
213
214 for variant in variants {
215 if let Some(path) = module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
216 // Variants with trivial paths are already added by the existing completion logic,
217 // so we should avoid adding these twice
218 if path.segments().len() > 1 {
219 cb(acc, ctx, variant, path);
220 }
221 }
222 }
223 }
224}