]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
Rollup merge of #94247 - saethlin:chunksmut-aliasing, r=the8472
[rust.git] / src / tools / rust-analyzer / crates / ide-completion / src / completions.rs
1 //! This module defines an accumulator for completions which are going to be presented to user.
2
3 pub(crate) mod attribute;
4 pub(crate) mod dot;
5 pub(crate) mod expr;
6 pub(crate) mod extern_abi;
7 pub(crate) mod field;
8 pub(crate) mod flyimport;
9 pub(crate) mod fn_param;
10 pub(crate) mod format_string;
11 pub(crate) mod item_list;
12 pub(crate) mod keyword;
13 pub(crate) mod lifetime;
14 pub(crate) mod mod_;
15 pub(crate) mod pattern;
16 pub(crate) mod postfix;
17 pub(crate) mod record;
18 pub(crate) mod snippet;
19 pub(crate) mod r#type;
20 pub(crate) mod use_;
21 pub(crate) mod vis;
22
23 use std::iter;
24
25 use hir::{known, ScopeDef};
26 use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
27 use syntax::ast;
28
29 use crate::{
30     context::{
31         DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind,
32         PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible,
33     },
34     item::Builder,
35     render::{
36         const_::render_const,
37         function::{render_fn, render_method},
38         literal::{render_struct_literal, render_variant_lit},
39         macro_::render_macro,
40         pattern::{render_struct_pat, render_variant_pat},
41         render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
42         type_alias::{render_type_alias, render_type_alias_with_eq},
43         union_literal::render_union_literal,
44         RenderContext,
45     },
46     CompletionContext, CompletionItem, CompletionItemKind,
47 };
48
49 /// Represents an in-progress set of completions being built.
50 #[derive(Debug, Default)]
51 pub struct Completions {
52     buf: Vec<CompletionItem>,
53 }
54
55 impl From<Completions> for Vec<CompletionItem> {
56     fn from(val: Completions) -> Self {
57         val.buf
58     }
59 }
60
61 impl Builder {
62     /// Convenience method, which allows to add a freshly created completion into accumulator
63     /// without binding it to the variable.
64     pub(crate) fn add_to(self, acc: &mut Completions) {
65         acc.add(self.build())
66     }
67 }
68
69 impl Completions {
70     fn add(&mut self, item: CompletionItem) {
71         self.buf.push(item)
72     }
73
74     fn add_opt(&mut self, item: Option<CompletionItem>) {
75         if let Some(item) = item {
76             self.buf.push(item)
77         }
78     }
79
80     pub(crate) fn add_all<I>(&mut self, items: I)
81     where
82         I: IntoIterator,
83         I::Item: Into<CompletionItem>,
84     {
85         items.into_iter().for_each(|item| self.add(item.into()))
86     }
87
88     pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) {
89         let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword);
90         item.add_to(self);
91     }
92
93     pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext<'_>) {
94         ["self::", "crate::"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
95
96         if ctx.depth_from_crate_root > 0 {
97             self.add_keyword(ctx, "super::");
98         }
99     }
100
101     pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) {
102         ["self", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
103
104         if ctx.depth_from_crate_root > 0 {
105             self.add_keyword(ctx, "super");
106         }
107     }
108
109     pub(crate) fn add_super_keyword(
110         &mut self,
111         ctx: &CompletionContext<'_>,
112         super_chain_len: Option<usize>,
113     ) {
114         if let Some(len) = super_chain_len {
115             if len > 0 && len < ctx.depth_from_crate_root {
116                 self.add_keyword(ctx, "super::");
117             }
118         }
119     }
120
121     pub(crate) fn add_keyword_snippet_expr(
122         &mut self,
123         ctx: &CompletionContext<'_>,
124         incomplete_let: bool,
125         kw: &str,
126         snippet: &str,
127     ) {
128         let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
129
130         match ctx.config.snippet_cap {
131             Some(cap) => {
132                 if incomplete_let && snippet.ends_with('}') {
133                     // complete block expression snippets with a trailing semicolon, if inside an incomplete let
134                     cov_mark::hit!(let_semi);
135                     item.insert_snippet(cap, format!("{};", snippet));
136                 } else {
137                     item.insert_snippet(cap, snippet);
138                 }
139             }
140             None => {
141                 item.insert_text(if snippet.contains('$') { kw } else { snippet });
142             }
143         };
144         item.add_to(self);
145     }
146
147     pub(crate) fn add_keyword_snippet(
148         &mut self,
149         ctx: &CompletionContext<'_>,
150         kw: &str,
151         snippet: &str,
152     ) {
153         let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
154
155         match ctx.config.snippet_cap {
156             Some(cap) => item.insert_snippet(cap, snippet),
157             None => item.insert_text(if snippet.contains('$') { kw } else { snippet }),
158         };
159         item.add_to(self);
160     }
161
162     pub(crate) fn add_crate_roots(
163         &mut self,
164         ctx: &CompletionContext<'_>,
165         path_ctx: &PathCompletionCtx,
166     ) {
167         ctx.process_all_names(&mut |name, res| match res {
168             ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
169                 self.add_module(ctx, path_ctx, m, name);
170             }
171             _ => (),
172         });
173     }
174
175     pub(crate) fn add_path_resolution(
176         &mut self,
177         ctx: &CompletionContext<'_>,
178         path_ctx: &PathCompletionCtx,
179         local_name: hir::Name,
180         resolution: hir::ScopeDef,
181     ) {
182         let is_private_editable = match ctx.def_is_visible(&resolution) {
183             Visible::Yes => false,
184             Visible::Editable => true,
185             Visible::No => return,
186         };
187         self.add(
188             render_path_resolution(
189                 RenderContext::new(ctx).private_editable(is_private_editable),
190                 path_ctx,
191                 local_name,
192                 resolution,
193             )
194             .build(),
195         );
196     }
197
198     pub(crate) fn add_pattern_resolution(
199         &mut self,
200         ctx: &CompletionContext<'_>,
201         pattern_ctx: &PatternContext,
202         local_name: hir::Name,
203         resolution: hir::ScopeDef,
204     ) {
205         let is_private_editable = match ctx.def_is_visible(&resolution) {
206             Visible::Yes => false,
207             Visible::Editable => true,
208             Visible::No => return,
209         };
210         self.add(
211             render_pattern_resolution(
212                 RenderContext::new(ctx).private_editable(is_private_editable),
213                 pattern_ctx,
214                 local_name,
215                 resolution,
216             )
217             .build(),
218         );
219     }
220
221     pub(crate) fn add_enum_variants(
222         &mut self,
223         ctx: &CompletionContext<'_>,
224         path_ctx: &PathCompletionCtx,
225         e: hir::Enum,
226     ) {
227         e.variants(ctx.db)
228             .into_iter()
229             .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
230     }
231
232     pub(crate) fn add_module(
233         &mut self,
234         ctx: &CompletionContext<'_>,
235         path_ctx: &PathCompletionCtx,
236         module: hir::Module,
237         local_name: hir::Name,
238     ) {
239         self.add_path_resolution(
240             ctx,
241             path_ctx,
242             local_name,
243             hir::ScopeDef::ModuleDef(module.into()),
244         );
245     }
246
247     pub(crate) fn add_macro(
248         &mut self,
249         ctx: &CompletionContext<'_>,
250         path_ctx: &PathCompletionCtx,
251         mac: hir::Macro,
252         local_name: hir::Name,
253     ) {
254         let is_private_editable = match ctx.is_visible(&mac) {
255             Visible::Yes => false,
256             Visible::Editable => true,
257             Visible::No => return,
258         };
259         self.add(
260             render_macro(
261                 RenderContext::new(ctx).private_editable(is_private_editable),
262                 path_ctx,
263                 local_name,
264                 mac,
265             )
266             .build(),
267         );
268     }
269
270     pub(crate) fn add_function(
271         &mut self,
272         ctx: &CompletionContext<'_>,
273         path_ctx: &PathCompletionCtx,
274         func: hir::Function,
275         local_name: Option<hir::Name>,
276     ) {
277         let is_private_editable = match ctx.is_visible(&func) {
278             Visible::Yes => false,
279             Visible::Editable => true,
280             Visible::No => return,
281         };
282         self.add(
283             render_fn(
284                 RenderContext::new(ctx).private_editable(is_private_editable),
285                 path_ctx,
286                 local_name,
287                 func,
288             )
289             .build(),
290         );
291     }
292
293     pub(crate) fn add_method(
294         &mut self,
295         ctx: &CompletionContext<'_>,
296         dot_access: &DotAccess,
297         func: hir::Function,
298         receiver: Option<hir::Name>,
299         local_name: Option<hir::Name>,
300     ) {
301         let is_private_editable = match ctx.is_visible(&func) {
302             Visible::Yes => false,
303             Visible::Editable => true,
304             Visible::No => return,
305         };
306         self.add(
307             render_method(
308                 RenderContext::new(ctx).private_editable(is_private_editable),
309                 dot_access,
310                 receiver,
311                 local_name,
312                 func,
313             )
314             .build(),
315         );
316     }
317
318     pub(crate) fn add_method_with_import(
319         &mut self,
320         ctx: &CompletionContext<'_>,
321         dot_access: &DotAccess,
322         func: hir::Function,
323         import: LocatedImport,
324     ) {
325         let is_private_editable = match ctx.is_visible(&func) {
326             Visible::Yes => false,
327             Visible::Editable => true,
328             Visible::No => return,
329         };
330         self.add(
331             render_method(
332                 RenderContext::new(ctx)
333                     .private_editable(is_private_editable)
334                     .import_to_add(Some(import)),
335                 dot_access,
336                 None,
337                 None,
338                 func,
339             )
340             .build(),
341         );
342     }
343
344     pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
345         let is_private_editable = match ctx.is_visible(&konst) {
346             Visible::Yes => false,
347             Visible::Editable => true,
348             Visible::No => return,
349         };
350         self.add_opt(render_const(
351             RenderContext::new(ctx).private_editable(is_private_editable),
352             konst,
353         ));
354     }
355
356     pub(crate) fn add_type_alias(
357         &mut self,
358         ctx: &CompletionContext<'_>,
359         type_alias: hir::TypeAlias,
360     ) {
361         let is_private_editable = match ctx.is_visible(&type_alias) {
362             Visible::Yes => false,
363             Visible::Editable => true,
364             Visible::No => return,
365         };
366         self.add_opt(render_type_alias(
367             RenderContext::new(ctx).private_editable(is_private_editable),
368             type_alias,
369         ));
370     }
371
372     pub(crate) fn add_type_alias_with_eq(
373         &mut self,
374         ctx: &CompletionContext<'_>,
375         type_alias: hir::TypeAlias,
376     ) {
377         self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
378     }
379
380     pub(crate) fn add_qualified_enum_variant(
381         &mut self,
382         ctx: &CompletionContext<'_>,
383         path_ctx: &PathCompletionCtx,
384         variant: hir::Variant,
385         path: hir::ModPath,
386     ) {
387         if let Some(builder) =
388             render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path))
389         {
390             self.add(builder.build());
391         }
392     }
393
394     pub(crate) fn add_enum_variant(
395         &mut self,
396         ctx: &CompletionContext<'_>,
397         path_ctx: &PathCompletionCtx,
398         variant: hir::Variant,
399         local_name: Option<hir::Name>,
400     ) {
401         if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
402             cov_mark::hit!(enum_variant_pattern_path);
403             self.add_variant_pat(ctx, pat_ctx, variant, local_name);
404             return;
405         }
406
407         if let Some(builder) =
408             render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None)
409         {
410             self.add(builder.build());
411         }
412     }
413
414     pub(crate) fn add_field(
415         &mut self,
416         ctx: &CompletionContext<'_>,
417         dot_access: &DotAccess,
418         receiver: Option<hir::Name>,
419         field: hir::Field,
420         ty: &hir::Type,
421     ) {
422         let is_private_editable = match ctx.is_visible(&field) {
423             Visible::Yes => false,
424             Visible::Editable => true,
425             Visible::No => return,
426         };
427         let item = render_field(
428             RenderContext::new(ctx).private_editable(is_private_editable),
429             dot_access,
430             receiver,
431             field,
432             ty,
433         );
434         self.add(item);
435     }
436
437     pub(crate) fn add_struct_literal(
438         &mut self,
439         ctx: &CompletionContext<'_>,
440         path_ctx: &PathCompletionCtx,
441         strukt: hir::Struct,
442         path: Option<hir::ModPath>,
443         local_name: Option<hir::Name>,
444     ) {
445         if let Some(builder) =
446             render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
447         {
448             self.add(builder.build());
449         }
450     }
451
452     pub(crate) fn add_union_literal(
453         &mut self,
454         ctx: &CompletionContext<'_>,
455         un: hir::Union,
456         path: Option<hir::ModPath>,
457         local_name: Option<hir::Name>,
458     ) {
459         let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
460         self.add_opt(item);
461     }
462
463     pub(crate) fn add_tuple_field(
464         &mut self,
465         ctx: &CompletionContext<'_>,
466         receiver: Option<hir::Name>,
467         field: usize,
468         ty: &hir::Type,
469     ) {
470         let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
471         self.add(item);
472     }
473
474     pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) {
475         CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), name.to_smol_str())
476             .add_to(self)
477     }
478
479     pub(crate) fn add_label(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) {
480         CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()).add_to(self)
481     }
482
483     pub(crate) fn add_variant_pat(
484         &mut self,
485         ctx: &CompletionContext<'_>,
486         pattern_ctx: &PatternContext,
487         variant: hir::Variant,
488         local_name: Option<hir::Name>,
489     ) {
490         self.add_opt(render_variant_pat(
491             RenderContext::new(ctx),
492             pattern_ctx,
493             variant,
494             local_name.clone(),
495             None,
496         ));
497     }
498
499     pub(crate) fn add_qualified_variant_pat(
500         &mut self,
501         ctx: &CompletionContext<'_>,
502         pattern_ctx: &PatternContext,
503         variant: hir::Variant,
504         path: hir::ModPath,
505     ) {
506         let path = Some(&path);
507         self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path));
508     }
509
510     pub(crate) fn add_struct_pat(
511         &mut self,
512         ctx: &CompletionContext<'_>,
513         pattern_ctx: &PatternContext,
514         strukt: hir::Struct,
515         local_name: Option<hir::Name>,
516     ) {
517         self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
518     }
519 }
520
521 /// Calls the callback for each variant of the provided enum with the path to the variant.
522 /// Skips variants that are visible with single segment paths.
523 fn enum_variants_with_paths(
524     acc: &mut Completions,
525     ctx: &CompletionContext<'_>,
526     enum_: hir::Enum,
527     impl_: &Option<ast::Impl>,
528     cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath),
529 ) {
530     let variants = enum_.variants(ctx.db);
531
532     if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
533         if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
534             for &variant in &variants {
535                 let self_path = hir::ModPath::from_segments(
536                     hir::PathKind::Plain,
537                     iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
538                 );
539                 cb(acc, ctx, variant, self_path);
540             }
541         }
542     }
543
544     for variant in variants {
545         if let Some(path) = ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
546             // Variants with trivial paths are already added by the existing completion logic,
547             // so we should avoid adding these twice
548             if path.segments().len() > 1 {
549                 cb(acc, ctx, variant, path);
550             }
551         }
552     }
553 }
554
555 pub(super) fn complete_name(
556     acc: &mut Completions,
557     ctx: &CompletionContext<'_>,
558     NameContext { name, kind }: &NameContext,
559 ) {
560     match kind {
561         NameKind::Const => {
562             item_list::trait_impl::complete_trait_impl_const(acc, ctx, name);
563         }
564         NameKind::Function => {
565             item_list::trait_impl::complete_trait_impl_fn(acc, ctx, name);
566         }
567         NameKind::IdentPat(pattern_ctx) => {
568             if ctx.token.kind() != syntax::T![_] {
569                 complete_patterns(acc, ctx, pattern_ctx)
570             }
571         }
572         NameKind::Module(mod_under_caret) => {
573             mod_::complete_mod(acc, ctx, mod_under_caret);
574         }
575         NameKind::TypeAlias => {
576             item_list::trait_impl::complete_trait_impl_type_alias(acc, ctx, name);
577         }
578         NameKind::RecordField => {
579             field::complete_field_list_record_variant(acc, ctx);
580         }
581         NameKind::ConstParam
582         | NameKind::Enum
583         | NameKind::MacroDef
584         | NameKind::MacroRules
585         | NameKind::Rename
586         | NameKind::SelfParam
587         | NameKind::Static
588         | NameKind::Struct
589         | NameKind::Trait
590         | NameKind::TypeParam
591         | NameKind::Union
592         | NameKind::Variant => (),
593     }
594 }
595
596 pub(super) fn complete_name_ref(
597     acc: &mut Completions,
598     ctx: &CompletionContext<'_>,
599     NameRefContext { nameref, kind }: &NameRefContext,
600 ) {
601     match kind {
602         NameRefKind::Path(path_ctx) => {
603             flyimport::import_on_the_fly_path(acc, ctx, path_ctx);
604
605             match &path_ctx.kind {
606                 PathKind::Expr { expr_ctx } => {
607                     expr::complete_expr_path(acc, ctx, path_ctx, expr_ctx);
608
609                     dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx);
610                     item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx);
611                     record::complete_record_expr_func_update(acc, ctx, path_ctx, expr_ctx);
612                     snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx);
613                 }
614                 PathKind::Type { location } => {
615                     r#type::complete_type_path(acc, ctx, path_ctx, location);
616
617                     match location {
618                         TypeLocation::TupleField => {
619                             field::complete_field_list_tuple_variant(acc, ctx, path_ctx);
620                         }
621                         TypeLocation::TypeAscription(ascription) => {
622                             r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription);
623                         }
624                         TypeLocation::GenericArgList(_)
625                         | TypeLocation::TypeBound
626                         | TypeLocation::ImplTarget
627                         | TypeLocation::ImplTrait
628                         | TypeLocation::Other => (),
629                     }
630                 }
631                 PathKind::Attr { attr_ctx } => {
632                     attribute::complete_attribute_path(acc, ctx, path_ctx, attr_ctx);
633                 }
634                 PathKind::Derive { existing_derives } => {
635                     attribute::complete_derive_path(acc, ctx, path_ctx, existing_derives);
636                 }
637                 PathKind::Item { kind } => {
638                     item_list::complete_item_list(acc, ctx, path_ctx, kind);
639
640                     snippet::complete_item_snippet(acc, ctx, path_ctx, kind);
641                     if let ItemListKind::TraitImpl(impl_) = kind {
642                         item_list::trait_impl::complete_trait_impl_item_by_name(
643                             acc, ctx, path_ctx, nameref, impl_,
644                         );
645                     }
646                 }
647                 PathKind::Pat { .. } => {
648                     pattern::complete_pattern_path(acc, ctx, path_ctx);
649                 }
650                 PathKind::Vis { has_in_token } => {
651                     vis::complete_vis_path(acc, ctx, path_ctx, has_in_token);
652                 }
653                 PathKind::Use => {
654                     use_::complete_use_path(acc, ctx, path_ctx, nameref);
655                 }
656             }
657         }
658         NameRefKind::DotAccess(dot_access) => {
659             flyimport::import_on_the_fly_dot(acc, ctx, dot_access);
660             dot::complete_dot(acc, ctx, dot_access);
661             postfix::complete_postfix(acc, ctx, dot_access);
662         }
663         NameRefKind::Keyword(item) => {
664             keyword::complete_for_and_where(acc, ctx, item);
665         }
666         NameRefKind::RecordExpr { dot_prefix, expr } => {
667             record::complete_record_expr_fields(acc, ctx, expr, dot_prefix);
668         }
669         NameRefKind::Pattern(pattern_ctx) => complete_patterns(acc, ctx, pattern_ctx),
670     }
671 }
672
673 fn complete_patterns(
674     acc: &mut Completions,
675     ctx: &CompletionContext<'_>,
676     pattern_ctx: &PatternContext,
677 ) {
678     flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx);
679     fn_param::complete_fn_param(acc, ctx, pattern_ctx);
680     pattern::complete_pattern(acc, ctx, pattern_ctx);
681     record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
682 }