|  | //! This module defines an accumulator for completions which are going to be presented to user. | 
|  |  | 
|  | pub(crate) mod attribute; | 
|  | pub(crate) mod dot; | 
|  | pub(crate) mod env_vars; | 
|  | pub(crate) mod expr; | 
|  | pub(crate) mod extern_abi; | 
|  | pub(crate) mod extern_crate; | 
|  | pub(crate) mod field; | 
|  | pub(crate) mod flyimport; | 
|  | pub(crate) mod fn_param; | 
|  | pub(crate) mod format_string; | 
|  | pub(crate) mod item_list; | 
|  | pub(crate) mod keyword; | 
|  | pub(crate) mod lifetime; | 
|  | pub(crate) mod mod_; | 
|  | pub(crate) mod pattern; | 
|  | pub(crate) mod postfix; | 
|  | pub(crate) mod record; | 
|  | pub(crate) mod snippet; | 
|  | pub(crate) mod r#type; | 
|  | pub(crate) mod use_; | 
|  | pub(crate) mod vis; | 
|  |  | 
|  | use std::iter; | 
|  |  | 
|  | use hir::{HasAttrs, Name, ScopeDef, Variant, sym}; | 
|  | use ide_db::{RootDatabase, SymbolKind, imports::import_assets::LocatedImport}; | 
|  | use syntax::{SmolStr, ToSmolStr, ast}; | 
|  |  | 
|  | use crate::{ | 
|  | CompletionContext, CompletionItem, CompletionItemKind, | 
|  | context::{ | 
|  | DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind, | 
|  | PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible, | 
|  | }, | 
|  | item::Builder, | 
|  | render::{ | 
|  | RenderContext, | 
|  | const_::render_const, | 
|  | function::{render_fn, render_method}, | 
|  | literal::{render_struct_literal, render_variant_lit}, | 
|  | macro_::render_macro, | 
|  | pattern::{render_struct_pat, render_variant_pat}, | 
|  | render_expr, render_field, render_path_resolution, render_pattern_resolution, | 
|  | render_tuple_field, | 
|  | type_alias::{render_type_alias, render_type_alias_with_eq}, | 
|  | union_literal::render_union_literal, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | /// Represents an in-progress set of completions being built. | 
|  | #[derive(Debug, Default)] | 
|  | pub struct Completions { | 
|  | buf: Vec<CompletionItem>, | 
|  | } | 
|  |  | 
|  | impl From<Completions> for Vec<CompletionItem> { | 
|  | fn from(val: Completions) -> Self { | 
|  | val.buf | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Builder { | 
|  | /// Convenience method, which allows to add a freshly created completion into accumulator | 
|  | /// without binding it to the variable. | 
|  | pub(crate) fn add_to(self, acc: &mut Completions, db: &RootDatabase) { | 
|  | acc.add(self.build(db)) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Completions { | 
|  | fn add(&mut self, item: CompletionItem) { | 
|  | self.buf.push(item) | 
|  | } | 
|  |  | 
|  | fn add_opt(&mut self, item: Option<CompletionItem>) { | 
|  | if let Some(item) = item { | 
|  | self.buf.push(item) | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) { | 
|  | let item = CompletionItem::new( | 
|  | CompletionItemKind::Keyword, | 
|  | ctx.source_range(), | 
|  | SmolStr::new_static(keyword), | 
|  | ctx.edition, | 
|  | ); | 
|  | item.add_to(self, ctx.db); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext<'_>) { | 
|  | ["self::", "crate::"].into_iter().for_each(|kw| self.add_keyword(ctx, kw)); | 
|  |  | 
|  | if ctx.depth_from_crate_root > 0 { | 
|  | self.add_keyword(ctx, "super::"); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) { | 
|  | ["self", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw)); | 
|  |  | 
|  | if ctx.depth_from_crate_root > 0 { | 
|  | self.add_keyword(ctx, "super"); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_super_keyword( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | super_chain_len: Option<usize>, | 
|  | ) { | 
|  | if let Some(len) = super_chain_len | 
|  | && len > 0 | 
|  | && len < ctx.depth_from_crate_root | 
|  | { | 
|  | self.add_keyword(ctx, "super::"); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_keyword_snippet_expr( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | incomplete_let: bool, | 
|  | kw: &str, | 
|  | snippet: &str, | 
|  | ) { | 
|  | let mut item = | 
|  | CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition); | 
|  |  | 
|  | match ctx.config.snippet_cap { | 
|  | Some(cap) => { | 
|  | if incomplete_let && snippet.ends_with('}') { | 
|  | // complete block expression snippets with a trailing semicolon, if inside an incomplete let | 
|  | cov_mark::hit!(let_semi); | 
|  | item.insert_snippet(cap, format!("{snippet};")); | 
|  | } else { | 
|  | item.insert_snippet(cap, snippet); | 
|  | } | 
|  | } | 
|  | None => { | 
|  | item.insert_text(if snippet.contains('$') { kw } else { snippet }); | 
|  | } | 
|  | }; | 
|  | item.add_to(self, ctx.db); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_keyword_snippet( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | kw: &str, | 
|  | snippet: &str, | 
|  | ) { | 
|  | let mut item = | 
|  | CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition); | 
|  |  | 
|  | match ctx.config.snippet_cap { | 
|  | Some(cap) => item.insert_snippet(cap, snippet), | 
|  | None => item.insert_text(if snippet.contains('$') { kw } else { snippet }), | 
|  | }; | 
|  | item.add_to(self, ctx.db); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_expr( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | expr: &hir::term_search::Expr<'_>, | 
|  | ) { | 
|  | if let Some(item) = render_expr(ctx, expr) { | 
|  | item.add_to(self, ctx.db) | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_crate_roots( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | ) { | 
|  | ctx.process_all_names(&mut |name, res, doc_aliases| match res { | 
|  | ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => { | 
|  | self.add_module(ctx, path_ctx, m, name, doc_aliases); | 
|  | } | 
|  | _ => (), | 
|  | }); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_path_resolution( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | local_name: hir::Name, | 
|  | resolution: hir::ScopeDef, | 
|  | doc_aliases: Vec<syntax::SmolStr>, | 
|  | ) { | 
|  | let is_private_editable = match ctx.def_is_visible(&resolution) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | self.add( | 
|  | render_path_resolution( | 
|  | RenderContext::new(ctx) | 
|  | .private_editable(is_private_editable) | 
|  | .doc_aliases(doc_aliases), | 
|  | path_ctx, | 
|  | local_name, | 
|  | resolution, | 
|  | ) | 
|  | .build(ctx.db), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_pattern_resolution( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | pattern_ctx: &PatternContext, | 
|  | local_name: hir::Name, | 
|  | resolution: hir::ScopeDef, | 
|  | ) { | 
|  | let is_private_editable = match ctx.def_is_visible(&resolution) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | self.add( | 
|  | render_pattern_resolution( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable), | 
|  | pattern_ctx, | 
|  | local_name, | 
|  | resolution, | 
|  | ) | 
|  | .build(ctx.db), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_enum_variants( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | e: hir::Enum, | 
|  | ) { | 
|  | if !ctx.check_stability_and_hidden(e) { | 
|  | return; | 
|  | } | 
|  | e.variants(ctx.db) | 
|  | .into_iter() | 
|  | .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None)); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_module( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | module: hir::Module, | 
|  | local_name: hir::Name, | 
|  | doc_aliases: Vec<syntax::SmolStr>, | 
|  | ) { | 
|  | self.add_path_resolution( | 
|  | ctx, | 
|  | path_ctx, | 
|  | local_name, | 
|  | hir::ScopeDef::ModuleDef(module.into()), | 
|  | doc_aliases, | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_macro( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | mac: hir::Macro, | 
|  | local_name: hir::Name, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&mac) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | self.add( | 
|  | render_macro( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable), | 
|  | path_ctx, | 
|  | local_name, | 
|  | mac, | 
|  | ) | 
|  | .build(ctx.db), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_function( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | func: hir::Function, | 
|  | local_name: Option<hir::Name>, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&func) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | let doc_aliases = ctx.doc_aliases(&func); | 
|  | self.add( | 
|  | render_fn( | 
|  | RenderContext::new(ctx) | 
|  | .private_editable(is_private_editable) | 
|  | .doc_aliases(doc_aliases), | 
|  | path_ctx, | 
|  | local_name, | 
|  | func, | 
|  | ) | 
|  | .build(ctx.db), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_method( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | dot_access: &DotAccess<'_>, | 
|  | func: hir::Function, | 
|  | receiver: Option<SmolStr>, | 
|  | local_name: Option<hir::Name>, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&func) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | let doc_aliases = ctx.doc_aliases(&func); | 
|  | self.add( | 
|  | render_method( | 
|  | RenderContext::new(ctx) | 
|  | .private_editable(is_private_editable) | 
|  | .doc_aliases(doc_aliases), | 
|  | dot_access, | 
|  | receiver, | 
|  | local_name, | 
|  | func, | 
|  | ) | 
|  | .build(ctx.db), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_method_with_import( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | dot_access: &DotAccess<'_>, | 
|  | func: hir::Function, | 
|  | import: LocatedImport, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&func) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | let doc_aliases = ctx.doc_aliases(&func); | 
|  | self.add( | 
|  | render_method( | 
|  | RenderContext::new(ctx) | 
|  | .private_editable(is_private_editable) | 
|  | .doc_aliases(doc_aliases) | 
|  | .import_to_add(Some(import)), | 
|  | dot_access, | 
|  | None, | 
|  | None, | 
|  | func, | 
|  | ) | 
|  | .build(ctx.db), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) { | 
|  | let is_private_editable = match ctx.is_visible(&konst) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | self.add_opt(render_const( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable), | 
|  | konst, | 
|  | )); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_type_alias( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | type_alias: hir::TypeAlias, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&type_alias) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | self.add_opt(render_type_alias( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable), | 
|  | type_alias, | 
|  | )); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_type_alias_with_eq( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | type_alias: hir::TypeAlias, | 
|  | ) { | 
|  | if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) { | 
|  | return; | 
|  | } | 
|  | self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_qualified_enum_variant( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | variant: hir::Variant, | 
|  | path: hir::ModPath, | 
|  | ) { | 
|  | if !ctx.check_stability_and_hidden(variant) { | 
|  | return; | 
|  | } | 
|  | if let Some(builder) = | 
|  | render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path)) | 
|  | { | 
|  | self.add(builder.build(ctx.db)); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_enum_variant( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | variant: hir::Variant, | 
|  | local_name: Option<hir::Name>, | 
|  | ) { | 
|  | if !ctx.check_stability_and_hidden(variant) { | 
|  | return; | 
|  | } | 
|  | if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx { | 
|  | cov_mark::hit!(enum_variant_pattern_path); | 
|  | self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if let Some(builder) = | 
|  | render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None) | 
|  | { | 
|  | self.add(builder.build(ctx.db)); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_field( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | dot_access: &DotAccess<'_>, | 
|  | receiver: Option<SmolStr>, | 
|  | field: hir::Field, | 
|  | ty: &hir::Type<'_>, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&field) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | let doc_aliases = ctx.doc_aliases(&field); | 
|  | let item = render_field( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable).doc_aliases(doc_aliases), | 
|  | dot_access, | 
|  | receiver, | 
|  | field, | 
|  | ty, | 
|  | ); | 
|  | self.add(item); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_struct_literal( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | path_ctx: &PathCompletionCtx<'_>, | 
|  | strukt: hir::Struct, | 
|  | path: Option<hir::ModPath>, | 
|  | local_name: Option<hir::Name>, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&strukt) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | if let Some(builder) = render_struct_literal( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable), | 
|  | path_ctx, | 
|  | strukt, | 
|  | path, | 
|  | local_name, | 
|  | ) { | 
|  | self.add(builder.build(ctx.db)); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_union_literal( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | un: hir::Union, | 
|  | path: Option<hir::ModPath>, | 
|  | local_name: Option<hir::Name>, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&un) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | let item = render_union_literal( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable), | 
|  | un, | 
|  | path, | 
|  | local_name, | 
|  | ); | 
|  | self.add_opt(item); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_tuple_field( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | receiver: Option<SmolStr>, | 
|  | field: usize, | 
|  | ty: &hir::Type<'_>, | 
|  | ) { | 
|  | // Only used for (unnamed) tuples, whose all fields *are* stable. No need to check | 
|  | // stability here. | 
|  | let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); | 
|  | self.add(item); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) { | 
|  | CompletionItem::new( | 
|  | SymbolKind::LifetimeParam, | 
|  | ctx.source_range(), | 
|  | name.display_no_db(ctx.edition).to_smolstr(), | 
|  | ctx.edition, | 
|  | ) | 
|  | .add_to(self, ctx.db) | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_label(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) { | 
|  | CompletionItem::new( | 
|  | SymbolKind::Label, | 
|  | ctx.source_range(), | 
|  | name.display_no_db(ctx.edition).to_smolstr(), | 
|  | ctx.edition, | 
|  | ) | 
|  | .add_to(self, ctx.db) | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_variant_pat( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | pattern_ctx: &PatternContext, | 
|  | path_ctx: Option<&PathCompletionCtx<'_>>, | 
|  | variant: hir::Variant, | 
|  | local_name: Option<hir::Name>, | 
|  | ) { | 
|  | if !ctx.check_stability_and_hidden(variant) { | 
|  | return; | 
|  | } | 
|  | self.add_opt(render_variant_pat( | 
|  | RenderContext::new(ctx), | 
|  | pattern_ctx, | 
|  | path_ctx, | 
|  | variant, | 
|  | local_name, | 
|  | None, | 
|  | )); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_qualified_variant_pat( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | pattern_ctx: &PatternContext, | 
|  | variant: hir::Variant, | 
|  | path: hir::ModPath, | 
|  | ) { | 
|  | if !ctx.check_stability_and_hidden(variant) { | 
|  | return; | 
|  | } | 
|  | let path = Some(&path); | 
|  | self.add_opt(render_variant_pat( | 
|  | RenderContext::new(ctx), | 
|  | pattern_ctx, | 
|  | None, | 
|  | variant, | 
|  | None, | 
|  | path, | 
|  | )); | 
|  | } | 
|  |  | 
|  | pub(crate) fn add_struct_pat( | 
|  | &mut self, | 
|  | ctx: &CompletionContext<'_>, | 
|  | pattern_ctx: &PatternContext, | 
|  | strukt: hir::Struct, | 
|  | local_name: Option<hir::Name>, | 
|  | ) { | 
|  | let is_private_editable = match ctx.is_visible(&strukt) { | 
|  | Visible::Yes => false, | 
|  | Visible::Editable => true, | 
|  | Visible::No => return, | 
|  | }; | 
|  | self.add_opt(render_struct_pat( | 
|  | RenderContext::new(ctx).private_editable(is_private_editable), | 
|  | pattern_ctx, | 
|  | strukt, | 
|  | local_name, | 
|  | )); | 
|  | } | 
|  |  | 
|  | pub(crate) fn suggest_name(&mut self, ctx: &CompletionContext<'_>, name: &str) { | 
|  | let item = CompletionItem::new( | 
|  | CompletionItemKind::Binding, | 
|  | ctx.source_range(), | 
|  | SmolStr::from(name), | 
|  | ctx.edition, | 
|  | ); | 
|  | item.add_to(self, ctx.db); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Calls the callback for each variant of the provided enum with the path to the variant. | 
|  | /// Skips variants that are visible with single segment paths. | 
|  | fn enum_variants_with_paths( | 
|  | acc: &mut Completions, | 
|  | ctx: &CompletionContext<'_>, | 
|  | enum_: hir::Enum, | 
|  | impl_: &Option<ast::Impl>, | 
|  | cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath), | 
|  | ) { | 
|  | let mut process_variant = |variant: Variant| { | 
|  | let self_path = hir::ModPath::from_segments( | 
|  | hir::PathKind::Plain, | 
|  | iter::once(Name::new_symbol_root(sym::Self_)).chain(iter::once(variant.name(ctx.db))), | 
|  | ); | 
|  |  | 
|  | cb(acc, ctx, variant, self_path); | 
|  | }; | 
|  |  | 
|  | let variants = enum_.variants(ctx.db); | 
|  |  | 
|  | if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) | 
|  | && impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) | 
|  | { | 
|  | variants.iter().for_each(|variant| process_variant(*variant)); | 
|  | } | 
|  |  | 
|  | for variant in variants { | 
|  | if let Some(path) = ctx.module.find_path( | 
|  | ctx.db, | 
|  | hir::ModuleDef::from(variant), | 
|  | ctx.config.import_path_config(ctx.is_nightly), | 
|  | ) { | 
|  | // Variants with trivial paths are already added by the existing completion logic, | 
|  | // so we should avoid adding these twice | 
|  | if path.segments().len() > 1 { | 
|  | cb(acc, ctx, variant, path); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(super) fn complete_name( | 
|  | acc: &mut Completions, | 
|  | ctx: &CompletionContext<'_>, | 
|  | NameContext { name, kind }: &NameContext, | 
|  | ) { | 
|  | match kind { | 
|  | NameKind::Const => { | 
|  | item_list::trait_impl::complete_trait_impl_const(acc, ctx, name); | 
|  | } | 
|  | NameKind::Function => { | 
|  | item_list::trait_impl::complete_trait_impl_fn(acc, ctx, name); | 
|  | } | 
|  | NameKind::IdentPat(pattern_ctx) => { | 
|  | if ctx.token.kind() != syntax::T![_] { | 
|  | complete_patterns(acc, ctx, pattern_ctx) | 
|  | } | 
|  | } | 
|  | NameKind::Module(mod_under_caret) => { | 
|  | mod_::complete_mod(acc, ctx, mod_under_caret); | 
|  | } | 
|  | NameKind::TypeAlias => { | 
|  | item_list::trait_impl::complete_trait_impl_type_alias(acc, ctx, name); | 
|  | } | 
|  | NameKind::RecordField => { | 
|  | field::complete_field_list_record_variant(acc, ctx); | 
|  | } | 
|  | NameKind::ConstParam | 
|  | | NameKind::Enum | 
|  | | NameKind::MacroDef | 
|  | | NameKind::MacroRules | 
|  | | NameKind::Rename | 
|  | | NameKind::SelfParam | 
|  | | NameKind::Static | 
|  | | NameKind::Struct | 
|  | | NameKind::Trait | 
|  | | NameKind::TypeParam | 
|  | | NameKind::Union | 
|  | | NameKind::Variant => (), | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(super) fn complete_name_ref( | 
|  | acc: &mut Completions, | 
|  | ctx: &CompletionContext<'_>, | 
|  | NameRefContext { nameref, kind }: &NameRefContext<'_>, | 
|  | ) { | 
|  | match kind { | 
|  | NameRefKind::Path(path_ctx) => { | 
|  | flyimport::import_on_the_fly_path(acc, ctx, path_ctx); | 
|  |  | 
|  | match &path_ctx.kind { | 
|  | PathKind::Expr { expr_ctx } => { | 
|  | expr::complete_expr_path(acc, ctx, path_ctx, expr_ctx); | 
|  | expr::complete_expr(acc, ctx); | 
|  |  | 
|  | dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx); | 
|  | item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx); | 
|  | snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx); | 
|  | } | 
|  | PathKind::Type { location } => { | 
|  | r#type::complete_type_path(acc, ctx, path_ctx, location); | 
|  |  | 
|  | match location { | 
|  | TypeLocation::TupleField => { | 
|  | field::complete_field_list_tuple_variant(acc, ctx, path_ctx); | 
|  | } | 
|  | TypeLocation::TypeAscription(ascription) => { | 
|  | r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription); | 
|  | } | 
|  | TypeLocation::GenericArg { .. } | 
|  | | TypeLocation::AssocConstEq | 
|  | | TypeLocation::AssocTypeEq | 
|  | | TypeLocation::TypeBound | 
|  | | TypeLocation::ImplTarget | 
|  | | TypeLocation::ImplTrait | 
|  | | TypeLocation::Other => (), | 
|  | } | 
|  | } | 
|  | PathKind::Attr { attr_ctx } => { | 
|  | attribute::complete_attribute_path(acc, ctx, path_ctx, attr_ctx); | 
|  | } | 
|  | PathKind::Derive { existing_derives } => { | 
|  | attribute::complete_derive_path(acc, ctx, path_ctx, existing_derives); | 
|  | } | 
|  | PathKind::Item { kind } => { | 
|  | item_list::complete_item_list(acc, ctx, path_ctx, kind); | 
|  |  | 
|  | snippet::complete_item_snippet(acc, ctx, path_ctx, kind); | 
|  | if let ItemListKind::TraitImpl(impl_) = kind { | 
|  | item_list::trait_impl::complete_trait_impl_item_by_name( | 
|  | acc, ctx, path_ctx, nameref, impl_, | 
|  | ); | 
|  | } | 
|  | } | 
|  | PathKind::Pat { .. } => { | 
|  | pattern::complete_pattern_path(acc, ctx, path_ctx); | 
|  | } | 
|  | PathKind::Vis { has_in_token } => { | 
|  | vis::complete_vis_path(acc, ctx, path_ctx, has_in_token); | 
|  | } | 
|  | PathKind::Use => { | 
|  | use_::complete_use_path(acc, ctx, path_ctx, nameref); | 
|  | } | 
|  | } | 
|  | } | 
|  | NameRefKind::ExternCrate => extern_crate::complete_extern_crate(acc, ctx), | 
|  | NameRefKind::DotAccess(dot_access) => { | 
|  | flyimport::import_on_the_fly_dot(acc, ctx, dot_access); | 
|  | dot::complete_dot(acc, ctx, dot_access); | 
|  | postfix::complete_postfix(acc, ctx, dot_access); | 
|  | } | 
|  | NameRefKind::Keyword(item) => { | 
|  | keyword::complete_for_and_where(acc, ctx, item); | 
|  | } | 
|  | NameRefKind::RecordExpr { dot_prefix, expr } => { | 
|  | record::complete_record_expr_fields(acc, ctx, expr, dot_prefix); | 
|  | } | 
|  | NameRefKind::Pattern(pattern_ctx) => complete_patterns(acc, ctx, pattern_ctx), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn complete_patterns( | 
|  | acc: &mut Completions, | 
|  | ctx: &CompletionContext<'_>, | 
|  | pattern_ctx: &PatternContext, | 
|  | ) { | 
|  | flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx); | 
|  | fn_param::complete_fn_param(acc, ctx, pattern_ctx); | 
|  | pattern::complete_pattern(acc, ctx, pattern_ctx); | 
|  | record::complete_record_pattern_fields(acc, ctx, pattern_ctx); | 
|  | } |