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