1mod analysis;
4#[cfg(test)]
5mod tests;
6
7use std::iter;
8
9use base_db::toolchain_channel;
10use hir::{
11 DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
12 ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
13};
14use ide_db::{
15 FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
16 helpers::is_editable_crate, syntax_helpers::node_ext::is_in_macro_matcher,
17};
18use itertools::Either;
19use syntax::{
20 AstNode, Edition, SmolStr,
21 SyntaxKind::{self, *},
22 SyntaxToken, T, TextRange, TextSize,
23 ast::{self, AttrKind, NameOrNameRef},
24};
25
26use crate::{
27 CompletionConfig,
28 config::AutoImportExclusionType,
29 context::analysis::{AnalysisResult, expand_and_analyze},
30};
31
32const COMPLETION_MARKER: &str = "raCompletionMarker";
33
34#[derive(Copy, Clone, Debug, PartialEq, Eq)]
35pub(crate) enum PatternRefutability {
36 Refutable,
37 Irrefutable,
38}
39
40#[derive(Debug)]
41pub(crate) enum Visible {
42 Yes,
43 Editable,
44 No,
45}
46
47#[derive(Debug, Default)]
49pub(crate) struct QualifierCtx {
50 pub(crate) async_tok: Option<SyntaxToken>,
52 pub(crate) unsafe_tok: Option<SyntaxToken>,
53 pub(crate) safe_tok: Option<SyntaxToken>,
54 pub(crate) vis_node: Option<ast::Visibility>,
55 pub(crate) abi_node: Option<ast::Abi>,
56}
57
58impl QualifierCtx {
59 pub(crate) fn none(&self) -> bool {
60 self.async_tok.is_none()
61 && self.unsafe_tok.is_none()
62 && self.safe_tok.is_none()
63 && self.vis_node.is_none()
64 && self.abi_node.is_none()
65 }
66}
67
68#[derive(Debug)]
70pub(crate) struct PathCompletionCtx<'db> {
71 pub(crate) has_call_parens: bool,
73 pub(crate) has_macro_bang: bool,
75 pub(crate) qualified: Qualified<'db>,
77 pub(crate) parent: Option<ast::Path>,
79 #[allow(dead_code)]
80 pub(crate) path: ast::Path,
82 pub(crate) original_path: Option<ast::Path>,
84 pub(crate) kind: PathKind<'db>,
85 pub(crate) has_type_args: bool,
87 pub(crate) use_tree_parent: bool,
89}
90
91impl PathCompletionCtx<'_> {
92 pub(crate) fn is_trivial_path(&self) -> bool {
93 matches!(
94 self,
95 PathCompletionCtx {
96 has_call_parens: false,
97 has_macro_bang: false,
98 qualified: Qualified::No,
99 parent: None,
100 has_type_args: false,
101 ..
102 }
103 )
104 }
105
106 pub(crate) fn required_thin_arrow(&self) -> Option<(&'static str, TextSize)> {
107 let PathKind::Type {
108 location:
109 TypeLocation::TypeAscription(TypeAscriptionTarget::RetType {
110 item: Some(ref fn_item),
111 ..
112 }),
113 } = self.kind
114 else {
115 return None;
116 };
117 if fn_item.ret_type().is_some_and(|it| it.thin_arrow_token().is_some()) {
118 return None;
119 }
120 let ret_type = fn_item.ret_type().and_then(|it| it.ty());
121 match (ret_type, fn_item.param_list()) {
122 (Some(ty), _) => Some(("-> ", ty.syntax().text_range().start())),
123 (None, Some(param)) => Some((" ->", param.syntax().text_range().end())),
124 (None, None) => None,
125 }
126 }
127}
128
129#[derive(Debug, PartialEq, Eq)]
131pub(crate) enum PathKind<'db> {
132 Expr {
133 expr_ctx: PathExprCtx<'db>,
134 },
135 Type {
136 location: TypeLocation,
137 },
138 Attr {
139 attr_ctx: AttrCtx,
140 },
141 Derive {
142 existing_derives: ExistingDerives,
143 },
144 Item {
146 kind: ItemListKind,
147 },
148 Pat {
149 pat_ctx: PatternContext,
150 },
151 Vis {
152 has_in_token: bool,
153 },
154 Use,
155}
156
157pub(crate) type ExistingDerives = FxHashSet<hir::Macro>;
158
159#[derive(Debug, PartialEq, Eq)]
160pub(crate) struct AttrCtx {
161 pub(crate) kind: AttrKind,
162 pub(crate) annotated_item_kind: Option<SyntaxKind>,
163 pub(crate) derive_helpers: Vec<(Symbol, Symbol)>,
164}
165
166#[derive(Debug, PartialEq, Eq)]
167pub(crate) struct PathExprCtx<'db> {
168 pub(crate) in_block_expr: bool,
169 pub(crate) in_breakable: Option<BreakableKind>,
170 pub(crate) after_if_expr: bool,
171 pub(crate) before_else_kw: bool,
172 pub(crate) in_condition: bool,
174 pub(crate) incomplete_let: bool,
175 pub(crate) after_incomplete_let: bool,
176 pub(crate) in_value: bool,
177 pub(crate) ref_expr_parent: Option<ast::RefExpr>,
178 pub(crate) after_amp: bool,
179 pub(crate) is_func_update: Option<ast::RecordExpr>,
181 pub(crate) self_param: Option<Either<hir::SelfParam, hir::Param<'db>>>,
182 pub(crate) innermost_ret_ty: Option<hir::Type<'db>>,
183 pub(crate) innermost_breakable_ty: Option<hir::Type<'db>>,
184 pub(crate) impl_: Option<ast::Impl>,
185 pub(crate) in_match_guard: bool,
188}
189
190#[derive(Clone, Debug, PartialEq, Eq)]
192pub(crate) enum TypeLocation {
193 TupleField,
194 TypeAscription(TypeAscriptionTarget),
195 GenericArg {
197 args: Option<ast::GenericArgList>,
199 of_trait: Option<hir::Trait>,
201 corresponding_param: Option<ast::GenericParam>,
203 },
204 AssocTypeEq,
206 AssocConstEq,
208 TypeBound,
209 ImplTarget,
210 ImplTrait,
211 Other,
212}
213
214impl TypeLocation {
215 pub(crate) fn complete_lifetimes(&self) -> bool {
216 matches!(
217 self,
218 TypeLocation::GenericArg {
219 corresponding_param: Some(ast::GenericParam::LifetimeParam(_)),
220 ..
221 }
222 )
223 }
224
225 pub(crate) fn complete_consts(&self) -> bool {
226 matches!(
227 self,
228 TypeLocation::GenericArg {
229 corresponding_param: Some(ast::GenericParam::ConstParam(_)),
230 ..
231 } | TypeLocation::AssocConstEq
232 )
233 }
234
235 pub(crate) fn complete_types(&self) -> bool {
236 match self {
237 TypeLocation::GenericArg { corresponding_param: Some(param), .. } => {
238 matches!(param, ast::GenericParam::TypeParam(_))
239 }
240 TypeLocation::AssocConstEq => false,
241 TypeLocation::AssocTypeEq => true,
242 TypeLocation::ImplTrait => false,
243 _ => true,
244 }
245 }
246
247 pub(crate) fn complete_self_type(&self) -> bool {
248 self.complete_types() && !matches!(self, TypeLocation::ImplTarget | TypeLocation::ImplTrait)
249 }
250}
251
252#[derive(Clone, Debug, PartialEq, Eq)]
253pub(crate) enum TypeAscriptionTarget {
254 Let(Option<ast::Pat>),
255 FnParam(Option<ast::Pat>),
256 RetType { body: Option<ast::Expr>, item: Option<ast::Fn> },
257 Const(Option<ast::Expr>),
258}
259
260#[derive(Debug, PartialEq, Eq)]
262pub(crate) enum ItemListKind {
263 SourceFile,
264 Module,
265 Impl,
266 TraitImpl(Option<ast::Impl>),
267 Trait,
268 ExternBlock { is_unsafe: bool },
269}
270
271#[derive(Debug)]
272pub(crate) enum Qualified<'db> {
273 No,
274 With {
275 path: ast::Path,
276 resolution: Option<PathResolution>,
277 super_chain_len: Option<usize>,
288 },
289 TypeAnchor {
291 ty: Option<hir::Type<'db>>,
292 trait_: Option<hir::Trait>,
293 },
294 Absolute,
296}
297
298#[derive(Debug, Clone, PartialEq, Eq)]
300pub(crate) struct PatternContext {
301 pub(crate) refutability: PatternRefutability,
302 pub(crate) param_ctx: Option<ParamContext>,
303 pub(crate) has_type_ascription: bool,
304 pub(crate) should_suggest_name: bool,
305 pub(crate) after_if_expr: bool,
306 pub(crate) parent_pat: Option<ast::Pat>,
307 pub(crate) ref_token: Option<SyntaxToken>,
308 pub(crate) mut_token: Option<SyntaxToken>,
309 pub(crate) record_pat: Option<ast::RecordPat>,
311 pub(crate) impl_or_trait: Option<Either<ast::Impl, ast::Trait>>,
312 pub(crate) missing_variants: Vec<hir::EnumVariant>,
314}
315
316#[derive(Debug, Clone, PartialEq, Eq)]
317pub(crate) struct ParamContext {
318 pub(crate) param_list: ast::ParamList,
319 pub(crate) param: ast::Param,
320 pub(crate) kind: ParamKind,
321}
322
323#[derive(Debug)]
325pub(crate) struct LifetimeContext {
326 pub(crate) kind: LifetimeKind,
327}
328
329#[derive(Debug)]
331pub(crate) enum LifetimeKind {
332 LifetimeParam,
333 Lifetime { in_lifetime_param_bound: bool, def: Option<hir::GenericDef> },
334 LabelRef,
335 LabelDef,
336}
337
338#[derive(Debug)]
340pub(crate) struct NameContext {
341 #[allow(dead_code)]
342 pub(crate) name: Option<ast::Name>,
343 pub(crate) kind: NameKind,
344}
345
346#[derive(Debug)]
348#[allow(dead_code)]
349pub(crate) enum NameKind {
350 Const,
351 ConstParam,
352 Enum,
353 Function,
354 IdentPat(PatternContext),
355 MacroDef,
356 MacroRules,
357 Module(ast::Module),
359 RecordField,
360 Rename,
361 SelfParam,
362 Static,
363 Struct,
364 Trait,
365 TypeAlias,
366 TypeParam,
367 Union,
368 Variant,
369}
370
371#[derive(Debug)]
373pub(crate) struct NameRefContext<'db> {
374 pub(crate) nameref: Option<ast::NameRef>,
376 pub(crate) kind: NameRefKind<'db>,
377}
378
379#[derive(Debug)]
381pub(crate) enum NameRefKind<'db> {
382 Path(PathCompletionCtx<'db>),
383 DotAccess(DotAccess<'db>),
384 Keyword(ast::Item),
386 RecordExpr {
388 dot_prefix: bool,
389 expr: ast::RecordExpr,
390 },
391 Pattern(PatternContext),
392 ExternCrate,
393}
394
395#[derive(Debug)]
397pub(crate) enum CompletionAnalysis<'db> {
398 Name(NameContext),
399 NameRef(NameRefContext<'db>),
400 Lifetime(LifetimeContext),
401 String {
403 original: ast::String,
405 expanded: Option<ast::String>,
407 },
408 UnexpandedAttrTT {
410 colon_prefix: bool,
411 fake_attribute_under_caret: Option<ast::TokenTreeMeta>,
412 extern_crate: Option<ast::ExternCrate>,
413 },
414 CfgPredicate,
416 MacroSegment,
417}
418
419#[derive(Debug)]
421pub(crate) struct DotAccess<'db> {
422 pub(crate) receiver: Option<ast::Expr>,
423 pub(crate) receiver_ty: Option<TypeInfo<'db>>,
424 pub(crate) kind: DotAccessKind,
425 pub(crate) ctx: DotAccessExprCtx,
426}
427
428#[derive(Debug, Clone, Copy)]
429pub(crate) enum DotAccessKind {
430 Field {
431 receiver_is_ambiguous_float_literal: bool,
434 },
435 Method,
436}
437
438#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439pub(crate) struct DotAccessExprCtx {
440 pub(crate) in_block_expr: bool,
441 pub(crate) in_breakable: Option<BreakableKind>,
442}
443
444#[derive(Copy, Clone, Debug, PartialEq, Eq)]
445pub(crate) enum BreakableKind {
446 Loop,
447 For,
448 While,
449 Block,
450}
451
452#[derive(Clone, Debug, PartialEq, Eq)]
453pub(crate) enum ParamKind {
454 Function(ast::Fn),
455 Closure(ast::ClosureExpr),
456}
457
458#[derive(Debug)]
461pub(crate) struct CompletionContext<'a> {
462 pub(crate) sema: Semantics<'a, RootDatabase>,
463 pub(crate) scope: SemanticsScope<'a>,
464 pub(crate) db: &'a RootDatabase,
465 pub(crate) config: &'a CompletionConfig<'a>,
466 pub(crate) position: FilePosition,
467
468 pub(crate) trigger_character: Option<char>,
469 pub(crate) original_token: SyntaxToken,
471 pub(crate) token: SyntaxToken,
473 pub(crate) krate: hir::Crate,
475 pub(crate) display_target: DisplayTarget,
476 pub(crate) module: hir::Module,
478 pub(crate) containing_function: Option<hir::Function>,
480 pub(crate) is_nightly: bool,
482 pub(crate) edition: Edition,
485
486 pub(crate) expected_name: Option<NameOrNameRef>,
489 pub(crate) expected_type: Option<Type<'a>>,
491
492 pub(crate) qualifier_ctx: QualifierCtx,
493
494 pub(crate) locals: FxHashMap<Name, Local>,
495
496 pub(crate) depth_from_crate_root: usize,
503
504 pub(crate) exclude_flyimport: FxHashMap<ModuleDef, AutoImportExclusionType>,
509 pub(crate) exclude_traits: FxHashSet<hir::Trait>,
514
515 pub(crate) complete_semicolon: CompleteSemicolon,
517}
518
519#[derive(Debug)]
520pub(crate) enum CompleteSemicolon {
521 DoNotComplete,
522 CompleteSemi,
523 CompleteComma,
524}
525
526impl CompletionContext<'_> {
527 pub(crate) fn source_range(&self) -> TextRange {
529 let kind = self.original_token.kind();
530 match kind {
531 CHAR => {
532 cov_mark::hit!(completes_if_lifetime_without_idents);
534 TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
535 }
536 LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
537 _ if kind.is_any_identifier() => self.original_token.text_range(),
539 _ => TextRange::empty(self.position.offset),
540 }
541 }
542
543 pub(crate) fn famous_defs(&self) -> FamousDefs<'_, '_> {
544 FamousDefs(&self.sema, self.krate)
545 }
546
547 pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible {
549 match item {
550 ScopeDef::ModuleDef(def) => match def {
551 hir::ModuleDef::Module(it) => self.is_visible(it),
552 hir::ModuleDef::Function(it) => self.is_visible(it),
553 hir::ModuleDef::Adt(it) => self.is_visible(it),
554 hir::ModuleDef::EnumVariant(it) => self.is_visible(it),
555 hir::ModuleDef::Const(it) => self.is_visible(it),
556 hir::ModuleDef::Static(it) => self.is_visible(it),
557 hir::ModuleDef::Trait(it) => self.is_visible(it),
558 hir::ModuleDef::TypeAlias(it) => self.is_visible(it),
559 hir::ModuleDef::Macro(it) => self.is_visible(it),
560 hir::ModuleDef::BuiltinType(_) => Visible::Yes,
561 },
562 ScopeDef::GenericParam(_)
563 | ScopeDef::ImplSelfType(_)
564 | ScopeDef::AdtSelfType(_)
565 | ScopeDef::Local(_)
566 | ScopeDef::Label(_)
567 | ScopeDef::Unknown => Visible::Yes,
568 }
569 }
570
571 pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
573 where
574 I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
575 {
576 let vis = item.visibility(self.db);
577 let attrs = item.attrs(self.db);
578 self.is_visible_impl(&vis, &attrs, item.krate(self.db))
579 }
580
581 pub(crate) fn doc_aliases<I>(&self, item: &I) -> Vec<SmolStr>
582 where
583 I: hir::HasAttrs + Copy,
584 {
585 let attrs = item.attrs(self.db);
586 attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect()
587 }
588
589 pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool {
591 let attrs = item.attrs(self.db);
592 let krate = item.krate(self.db);
593 match (attrs, krate) {
594 (Some(attrs), Some(krate)) => self.is_doc_hidden(&attrs, krate),
595 _ => false,
596 }
597 }
598
599 pub(crate) fn check_stability(&self, attrs: Option<&hir::AttrsWithOwner>) -> bool {
601 let Some(attrs) = attrs else {
602 return true;
603 };
604 !attrs.is_unstable() || self.is_nightly
605 }
606
607 pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
608 where
609 I: hir::HasAttrs + hir::HasCrate,
610 {
611 let defining_crate = item.krate(self.db);
612 let attrs = item.attrs(self.db);
613 self.check_stability(Some(&attrs)) && !self.is_doc_hidden(&attrs, defining_crate)
614 }
615
616 pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
618 match trait_.attrs(self.db).lang(self.db) {
619 Some(lang) => OP_TRAIT_LANG.contains(&lang),
620 None => false,
621 }
622 }
623
624 pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool {
626 trait_.attrs(self.db).is_doc_notable_trait()
627 }
628
629 pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
631 let mut traits_in_scope = self.scope.visible_traits();
632 if let Some(drop) = self.famous_defs().core_ops_Drop() {
633 traits_in_scope.0.remove(&drop.into());
634 }
635 traits_in_scope
636 }
637
638 pub(crate) fn iterate_path_candidates(
639 &self,
640 ty: &hir::Type<'_>,
641 mut cb: impl FnMut(hir::AssocItem),
642 ) {
643 let mut seen = FxHashSet::default();
644 ty.iterate_path_candidates(self.db, &self.scope, &self.traits_in_scope(), None, |item| {
645 if seen.insert(item) {
648 cb(item)
649 }
650 None::<()>
651 });
652 }
653
654 pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec<SmolStr>)) {
657 let _p = tracing::info_span!("CompletionContext::process_all_names").entered();
658 self.scope.process_all_names(&mut |name, def| {
659 if self.is_scope_def_hidden(def) {
660 return;
661 }
662 let doc_aliases = self.doc_aliases_in_scope(def);
663 f(name, def, doc_aliases);
664 });
665 }
666
667 pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
668 let _p = tracing::info_span!("CompletionContext::process_all_names_raw").entered();
669 self.scope.process_all_names(f);
670 }
671
672 fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
673 if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) {
674 return self.is_doc_hidden(&attrs, krate);
675 }
676
677 false
678 }
679
680 fn is_visible_impl(
681 &self,
682 vis: &hir::Visibility,
683 attrs: &hir::AttrsWithOwner,
684 defining_crate: hir::Crate,
685 ) -> Visible {
686 if !self.check_stability(Some(attrs)) {
687 return Visible::No;
688 }
689
690 if !vis.is_visible_from(self.db, self.module.into()) {
691 if !self.config.enable_private_editable {
692 return Visible::No;
693 }
694 return if is_editable_crate(defining_crate, self.db) {
696 Visible::Editable
697 } else {
698 Visible::No
699 };
700 }
701
702 if self.is_doc_hidden(attrs, defining_crate) { Visible::No } else { Visible::Yes }
703 }
704
705 pub(crate) fn is_doc_hidden(
706 &self,
707 attrs: &hir::AttrsWithOwner,
708 defining_crate: hir::Crate,
709 ) -> bool {
710 self.krate != defining_crate && attrs.is_doc_hidden()
712 }
713
714 pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec<SmolStr> {
715 if let Some(attrs) = scope_def.attrs(self.db) {
716 attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect()
717 } else {
718 vec![]
719 }
720 }
721}
722
723impl<'db> CompletionContext<'db> {
725 pub(crate) fn new(
726 db: &'db RootDatabase,
727 position @ FilePosition { file_id, offset }: FilePosition,
728 config: &'db CompletionConfig<'db>,
729 trigger_character: Option<char>,
730 ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
731 let _p = tracing::info_span!("CompletionContext::new").entered();
732 let sema = Semantics::new(db);
733
734 let editioned_file_id = sema.attach_first_edition(file_id);
735 let original_file = sema.parse(editioned_file_id);
736
737 let file_with_fake_ident = {
741 let (_, edition) = editioned_file_id.unpack(db);
742 let parse = editioned_file_id.parse(db);
743 parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, edition).tree()
744 };
745
746 let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
749
750 if original_token.kind() == T![:] {
753 let prev_token = original_token.prev_token()?;
755
756 if prev_token.kind() != T![:] && !is_in_macro_matcher(&original_token) {
758 return None;
759 }
760
761 if prev_token
765 .prev_token()
766 .map(|t| t.kind() == T![:] || t.kind() == T![::])
767 .unwrap_or(false)
768 {
769 return None;
770 }
771 }
772
773 let AnalysisResult {
774 analysis,
775 expected: (expected_type, expected_name),
776 qualifier_ctx,
777 token,
778 original_offset,
779 } = expand_and_analyze(
780 &sema,
781 InFile::new(editioned_file_id.into(), original_file.syntax().clone()),
782 file_with_fake_ident.syntax().clone(),
783 offset,
784 &original_token,
785 )?;
786
787 let scope = sema.scope_at_offset(&token.parent()?, original_offset)?;
789
790 let krate = scope.krate();
791 let module = scope.module();
792 let containing_function = scope.containing_function();
793 let edition = krate.edition(db);
794
795 let toolchain = toolchain_channel(db, krate.into());
796 let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
799
800 let mut locals = FxHashMap::default();
801 scope.process_all_names(&mut |name, scope| {
802 if let ScopeDef::Local(local) = scope {
803 if name.as_str().starts_with('<') {
806 return;
807 }
808 locals.insert(name, local);
809 }
810 });
811
812 let depth_from_crate_root = iter::successors(Some(module), |m| m.parent(db))
813 .filter(|m| !matches!(m.definition_source(db).value, ModuleSource::BlockExpr(_)))
815 .count()
816 .saturating_sub(1);
818
819 let exclude_traits: FxHashSet<_> = config
820 .exclude_traits
821 .iter()
822 .filter_map(|path| {
823 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern)).find_map(
824 |it| match it {
825 hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
826 _ => None,
827 },
828 )
829 })
830 .collect();
831
832 let mut exclude_flyimport: FxHashMap<_, _> = config
833 .exclude_flyimport
834 .iter()
835 .flat_map(|(path, kind)| {
836 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern))
837 .map(|it| (it.into_module_def(), *kind))
838 })
839 .collect();
840 exclude_flyimport
841 .extend(exclude_traits.iter().map(|&t| (t.into(), AutoImportExclusionType::Always)));
842
843 let complete_semicolon = if !config.add_semicolon_to_unit {
845 CompleteSemicolon::DoNotComplete
846 } else if let Some(term_node) =
847 sema.token_ancestors_with_macros(token.clone()).find(|node| {
848 matches!(
849 node.kind(),
850 BLOCK_EXPR | MATCH_ARM | CLOSURE_EXPR | ARG_LIST | PAREN_EXPR | ARRAY_EXPR
851 )
852 })
853 {
854 let next_token = iter::successors(token.next_token(), |it| it.next_token())
855 .map(|it| it.kind())
856 .find(|kind| !kind.is_trivia());
857 match term_node.kind() {
858 MATCH_ARM if next_token != Some(T![,]) => CompleteSemicolon::CompleteComma,
859 BLOCK_EXPR if next_token != Some(T![;]) => CompleteSemicolon::CompleteSemi,
860 _ => CompleteSemicolon::DoNotComplete,
861 }
862 } else {
863 CompleteSemicolon::DoNotComplete
864 };
865
866 let display_target = krate.to_display_target(db);
867 let ctx = CompletionContext {
868 sema,
869 scope,
870 db,
871 config,
872 position,
873 trigger_character,
874 original_token,
875 token,
876 krate,
877 module,
878 containing_function,
879 is_nightly,
880 edition,
881 expected_name,
882 expected_type,
883 qualifier_ctx,
884 locals,
885 depth_from_crate_root,
886 exclude_flyimport,
887 exclude_traits,
888 complete_semicolon,
889 display_target,
890 };
891 Some((ctx, analysis))
892 }
893}
894
895const OP_TRAIT_LANG: &[hir::LangItem] = &[
896 hir::LangItem::AddAssign,
897 hir::LangItem::Add,
898 hir::LangItem::BitAndAssign,
899 hir::LangItem::BitAnd,
900 hir::LangItem::BitOrAssign,
901 hir::LangItem::BitOr,
902 hir::LangItem::BitXorAssign,
903 hir::LangItem::BitXor,
904 hir::LangItem::DerefMut,
905 hir::LangItem::Deref,
906 hir::LangItem::DivAssign,
907 hir::LangItem::Div,
908 hir::LangItem::PartialEq,
909 hir::LangItem::FnMut,
910 hir::LangItem::FnOnce,
911 hir::LangItem::Fn,
912 hir::LangItem::IndexMut,
913 hir::LangItem::Index,
914 hir::LangItem::MulAssign,
915 hir::LangItem::Mul,
916 hir::LangItem::Neg,
917 hir::LangItem::Not,
918 hir::LangItem::PartialOrd,
919 hir::LangItem::RemAssign,
920 hir::LangItem::Rem,
921 hir::LangItem::ShlAssign,
922 hir::LangItem::Shl,
923 hir::LangItem::ShrAssign,
924 hir::LangItem::Shr,
925 hir::LangItem::Sub,
926];