1mod analysis;
4#[cfg(test)]
5mod tests;
6
7use std::iter;
8
9use base_db::RootQueryDb as _;
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,
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
107#[derive(Debug, PartialEq, Eq)]
109pub(crate) enum PathKind<'db> {
110 Expr {
111 expr_ctx: PathExprCtx<'db>,
112 },
113 Type {
114 location: TypeLocation,
115 },
116 Attr {
117 attr_ctx: AttrCtx,
118 },
119 Derive {
120 existing_derives: ExistingDerives,
121 },
122 Item {
124 kind: ItemListKind,
125 },
126 Pat {
127 pat_ctx: PatternContext,
128 },
129 Vis {
130 has_in_token: bool,
131 },
132 Use,
133}
134
135pub(crate) type ExistingDerives = FxHashSet<hir::Macro>;
136
137#[derive(Debug, PartialEq, Eq)]
138pub(crate) struct AttrCtx {
139 pub(crate) kind: AttrKind,
140 pub(crate) annotated_item_kind: Option<SyntaxKind>,
141 pub(crate) derive_helpers: Vec<(Symbol, Symbol)>,
142}
143
144#[derive(Debug, PartialEq, Eq)]
145pub(crate) struct PathExprCtx<'db> {
146 pub(crate) in_block_expr: bool,
147 pub(crate) in_breakable: Option<BreakableKind>,
148 pub(crate) after_if_expr: bool,
149 pub(crate) before_else_kw: bool,
150 pub(crate) in_condition: bool,
152 pub(crate) incomplete_let: bool,
153 pub(crate) after_incomplete_let: bool,
154 pub(crate) in_value: bool,
155 pub(crate) ref_expr_parent: Option<ast::RefExpr>,
156 pub(crate) after_amp: bool,
157 pub(crate) is_func_update: Option<ast::RecordExpr>,
159 pub(crate) self_param: Option<hir::SelfParam>,
160 pub(crate) innermost_ret_ty: Option<hir::Type<'db>>,
161 pub(crate) innermost_breakable_ty: Option<hir::Type<'db>>,
162 pub(crate) impl_: Option<ast::Impl>,
163 pub(crate) in_match_guard: bool,
166}
167
168#[derive(Clone, Debug, PartialEq, Eq)]
170pub(crate) enum TypeLocation {
171 TupleField,
172 TypeAscription(TypeAscriptionTarget),
173 GenericArg {
175 args: Option<ast::GenericArgList>,
177 of_trait: Option<hir::Trait>,
179 corresponding_param: Option<ast::GenericParam>,
181 },
182 AssocTypeEq,
184 AssocConstEq,
186 TypeBound,
187 ImplTarget,
188 ImplTrait,
189 Other,
190}
191
192impl TypeLocation {
193 pub(crate) fn complete_lifetimes(&self) -> bool {
194 matches!(
195 self,
196 TypeLocation::GenericArg {
197 corresponding_param: Some(ast::GenericParam::LifetimeParam(_)),
198 ..
199 }
200 )
201 }
202
203 pub(crate) fn complete_consts(&self) -> bool {
204 matches!(
205 self,
206 TypeLocation::GenericArg {
207 corresponding_param: Some(ast::GenericParam::ConstParam(_)),
208 ..
209 } | TypeLocation::AssocConstEq
210 )
211 }
212
213 pub(crate) fn complete_types(&self) -> bool {
214 match self {
215 TypeLocation::GenericArg { corresponding_param: Some(param), .. } => {
216 matches!(param, ast::GenericParam::TypeParam(_))
217 }
218 TypeLocation::AssocConstEq => false,
219 TypeLocation::AssocTypeEq => true,
220 TypeLocation::ImplTrait => false,
221 _ => true,
222 }
223 }
224
225 pub(crate) fn complete_self_type(&self) -> bool {
226 self.complete_types() && !matches!(self, TypeLocation::ImplTarget | TypeLocation::ImplTrait)
227 }
228}
229
230#[derive(Clone, Debug, PartialEq, Eq)]
231pub(crate) enum TypeAscriptionTarget {
232 Let(Option<ast::Pat>),
233 FnParam(Option<ast::Pat>),
234 RetType(Option<ast::Expr>),
235 Const(Option<ast::Expr>),
236}
237
238#[derive(Debug, PartialEq, Eq)]
240pub(crate) enum ItemListKind {
241 SourceFile,
242 Module,
243 Impl,
244 TraitImpl(Option<ast::Impl>),
245 Trait,
246 ExternBlock { is_unsafe: bool },
247}
248
249#[derive(Debug)]
250pub(crate) enum Qualified<'db> {
251 No,
252 With {
253 path: ast::Path,
254 resolution: Option<PathResolution>,
255 super_chain_len: Option<usize>,
266 },
267 TypeAnchor {
269 ty: Option<hir::Type<'db>>,
270 trait_: Option<hir::Trait>,
271 },
272 Absolute,
274}
275
276#[derive(Debug, Clone, PartialEq, Eq)]
278pub(crate) struct PatternContext {
279 pub(crate) refutability: PatternRefutability,
280 pub(crate) param_ctx: Option<ParamContext>,
281 pub(crate) has_type_ascription: bool,
282 pub(crate) should_suggest_name: bool,
283 pub(crate) after_if_expr: bool,
284 pub(crate) parent_pat: Option<ast::Pat>,
285 pub(crate) ref_token: Option<SyntaxToken>,
286 pub(crate) mut_token: Option<SyntaxToken>,
287 pub(crate) record_pat: Option<ast::RecordPat>,
289 pub(crate) impl_or_trait: Option<Either<ast::Impl, ast::Trait>>,
290 pub(crate) missing_variants: Vec<hir::Variant>,
292}
293
294#[derive(Debug, Clone, PartialEq, Eq)]
295pub(crate) struct ParamContext {
296 pub(crate) param_list: ast::ParamList,
297 pub(crate) param: ast::Param,
298 pub(crate) kind: ParamKind,
299}
300
301#[derive(Debug)]
303pub(crate) struct LifetimeContext {
304 pub(crate) kind: LifetimeKind,
305}
306
307#[derive(Debug)]
309pub(crate) enum LifetimeKind {
310 LifetimeParam,
311 Lifetime { in_lifetime_param_bound: bool, def: Option<hir::GenericDef> },
312 LabelRef,
313 LabelDef,
314}
315
316#[derive(Debug)]
318pub(crate) struct NameContext {
319 #[allow(dead_code)]
320 pub(crate) name: Option<ast::Name>,
321 pub(crate) kind: NameKind,
322}
323
324#[derive(Debug)]
326#[allow(dead_code)]
327pub(crate) enum NameKind {
328 Const,
329 ConstParam,
330 Enum,
331 Function,
332 IdentPat(PatternContext),
333 MacroDef,
334 MacroRules,
335 Module(ast::Module),
337 RecordField,
338 Rename,
339 SelfParam,
340 Static,
341 Struct,
342 Trait,
343 TypeAlias,
344 TypeParam,
345 Union,
346 Variant,
347}
348
349#[derive(Debug)]
351pub(crate) struct NameRefContext<'db> {
352 pub(crate) nameref: Option<ast::NameRef>,
354 pub(crate) kind: NameRefKind<'db>,
355}
356
357#[derive(Debug)]
359pub(crate) enum NameRefKind<'db> {
360 Path(PathCompletionCtx<'db>),
361 DotAccess(DotAccess<'db>),
362 Keyword(ast::Item),
364 RecordExpr {
366 dot_prefix: bool,
367 expr: ast::RecordExpr,
368 },
369 Pattern(PatternContext),
370 ExternCrate,
371}
372
373#[derive(Debug)]
375pub(crate) enum CompletionAnalysis<'db> {
376 Name(NameContext),
377 NameRef(NameRefContext<'db>),
378 Lifetime(LifetimeContext),
379 String {
381 original: ast::String,
383 expanded: Option<ast::String>,
385 },
386 UnexpandedAttrTT {
388 colon_prefix: bool,
389 fake_attribute_under_caret: Option<ast::Attr>,
390 extern_crate: Option<ast::ExternCrate>,
391 },
392}
393
394#[derive(Debug)]
396pub(crate) struct DotAccess<'db> {
397 pub(crate) receiver: Option<ast::Expr>,
398 pub(crate) receiver_ty: Option<TypeInfo<'db>>,
399 pub(crate) kind: DotAccessKind,
400 pub(crate) ctx: DotAccessExprCtx,
401}
402
403#[derive(Debug, Clone, Copy)]
404pub(crate) enum DotAccessKind {
405 Field {
406 receiver_is_ambiguous_float_literal: bool,
409 },
410 Method,
411}
412
413#[derive(Debug, Clone, Copy, PartialEq, Eq)]
414pub(crate) struct DotAccessExprCtx {
415 pub(crate) in_block_expr: bool,
416 pub(crate) in_breakable: Option<BreakableKind>,
417}
418
419#[derive(Copy, Clone, Debug, PartialEq, Eq)]
420pub(crate) enum BreakableKind {
421 Loop,
422 For,
423 While,
424 Block,
425}
426
427#[derive(Clone, Debug, PartialEq, Eq)]
428pub(crate) enum ParamKind {
429 Function(ast::Fn),
430 Closure(ast::ClosureExpr),
431}
432
433#[derive(Debug)]
436pub(crate) struct CompletionContext<'a> {
437 pub(crate) sema: Semantics<'a, RootDatabase>,
438 pub(crate) scope: SemanticsScope<'a>,
439 pub(crate) db: &'a RootDatabase,
440 pub(crate) config: &'a CompletionConfig<'a>,
441 pub(crate) position: FilePosition,
442
443 pub(crate) trigger_character: Option<char>,
444 pub(crate) original_token: SyntaxToken,
446 pub(crate) token: SyntaxToken,
448 pub(crate) krate: hir::Crate,
450 pub(crate) display_target: DisplayTarget,
451 pub(crate) module: hir::Module,
453 pub(crate) containing_function: Option<hir::Function>,
455 pub(crate) is_nightly: bool,
457 pub(crate) edition: Edition,
460
461 pub(crate) expected_name: Option<NameOrNameRef>,
464 pub(crate) expected_type: Option<Type<'a>>,
466
467 pub(crate) qualifier_ctx: QualifierCtx,
468
469 pub(crate) locals: FxHashMap<Name, Local>,
470
471 pub(crate) depth_from_crate_root: usize,
478
479 pub(crate) exclude_flyimport: FxHashMap<ModuleDef, AutoImportExclusionType>,
484 pub(crate) exclude_traits: FxHashSet<hir::Trait>,
489
490 pub(crate) complete_semicolon: CompleteSemicolon,
492}
493
494#[derive(Debug)]
495pub(crate) enum CompleteSemicolon {
496 DoNotComplete,
497 CompleteSemi,
498 CompleteComma,
499}
500
501impl CompletionContext<'_> {
502 pub(crate) fn source_range(&self) -> TextRange {
504 let kind = self.original_token.kind();
505 match kind {
506 CHAR => {
507 cov_mark::hit!(completes_if_lifetime_without_idents);
509 TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
510 }
511 LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
512 _ if kind.is_any_identifier() => self.original_token.text_range(),
514 _ => TextRange::empty(self.position.offset),
515 }
516 }
517
518 pub(crate) fn famous_defs(&self) -> FamousDefs<'_, '_> {
519 FamousDefs(&self.sema, self.krate)
520 }
521
522 pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible {
524 match item {
525 ScopeDef::ModuleDef(def) => match def {
526 hir::ModuleDef::Module(it) => self.is_visible(it),
527 hir::ModuleDef::Function(it) => self.is_visible(it),
528 hir::ModuleDef::Adt(it) => self.is_visible(it),
529 hir::ModuleDef::Variant(it) => self.is_visible(it),
530 hir::ModuleDef::Const(it) => self.is_visible(it),
531 hir::ModuleDef::Static(it) => self.is_visible(it),
532 hir::ModuleDef::Trait(it) => self.is_visible(it),
533 hir::ModuleDef::TypeAlias(it) => self.is_visible(it),
534 hir::ModuleDef::Macro(it) => self.is_visible(it),
535 hir::ModuleDef::BuiltinType(_) => Visible::Yes,
536 },
537 ScopeDef::GenericParam(_)
538 | ScopeDef::ImplSelfType(_)
539 | ScopeDef::AdtSelfType(_)
540 | ScopeDef::Local(_)
541 | ScopeDef::Label(_)
542 | ScopeDef::Unknown => Visible::Yes,
543 }
544 }
545
546 pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
548 where
549 I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
550 {
551 let vis = item.visibility(self.db);
552 let attrs = item.attrs(self.db);
553 self.is_visible_impl(&vis, &attrs, item.krate(self.db))
554 }
555
556 pub(crate) fn doc_aliases<I>(&self, item: &I) -> Vec<SmolStr>
557 where
558 I: hir::HasAttrs + Copy,
559 {
560 let attrs = item.attrs(self.db);
561 attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect()
562 }
563
564 pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool {
566 let attrs = item.attrs(self.db);
567 let krate = item.krate(self.db);
568 match (attrs, krate) {
569 (Some(attrs), Some(krate)) => self.is_doc_hidden(&attrs, krate),
570 _ => false,
571 }
572 }
573
574 pub(crate) fn check_stability(&self, attrs: Option<&hir::AttrsWithOwner>) -> bool {
576 let Some(attrs) = attrs else {
577 return true;
578 };
579 !attrs.is_unstable() || self.is_nightly
580 }
581
582 pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
583 where
584 I: hir::HasAttrs + hir::HasCrate,
585 {
586 let defining_crate = item.krate(self.db);
587 let attrs = item.attrs(self.db);
588 self.check_stability(Some(&attrs)) && !self.is_doc_hidden(&attrs, defining_crate)
589 }
590
591 pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
593 match trait_.attrs(self.db).lang(self.db) {
594 Some(lang) => OP_TRAIT_LANG.contains(&lang),
595 None => false,
596 }
597 }
598
599 pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool {
601 trait_.attrs(self.db).is_doc_notable_trait()
602 }
603
604 pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
606 let mut traits_in_scope = self.scope.visible_traits();
607 if let Some(drop) = self.famous_defs().core_ops_Drop() {
608 traits_in_scope.0.remove(&drop.into());
609 }
610 traits_in_scope
611 }
612
613 pub(crate) fn iterate_path_candidates(
614 &self,
615 ty: &hir::Type<'_>,
616 mut cb: impl FnMut(hir::AssocItem),
617 ) {
618 let mut seen = FxHashSet::default();
619 ty.iterate_path_candidates(self.db, &self.scope, &self.traits_in_scope(), None, |item| {
620 if seen.insert(item) {
623 cb(item)
624 }
625 None::<()>
626 });
627 }
628
629 pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec<SmolStr>)) {
632 let _p = tracing::info_span!("CompletionContext::process_all_names").entered();
633 self.scope.process_all_names(&mut |name, def| {
634 if self.is_scope_def_hidden(def) {
635 return;
636 }
637 let doc_aliases = self.doc_aliases_in_scope(def);
638 f(name, def, doc_aliases);
639 });
640 }
641
642 pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
643 let _p = tracing::info_span!("CompletionContext::process_all_names_raw").entered();
644 self.scope.process_all_names(f);
645 }
646
647 fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
648 if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) {
649 return self.is_doc_hidden(&attrs, krate);
650 }
651
652 false
653 }
654
655 fn is_visible_impl(
656 &self,
657 vis: &hir::Visibility,
658 attrs: &hir::AttrsWithOwner,
659 defining_crate: hir::Crate,
660 ) -> Visible {
661 if !self.check_stability(Some(attrs)) {
662 return Visible::No;
663 }
664
665 if !vis.is_visible_from(self.db, self.module.into()) {
666 if !self.config.enable_private_editable {
667 return Visible::No;
668 }
669 return if is_editable_crate(defining_crate, self.db) {
671 Visible::Editable
672 } else {
673 Visible::No
674 };
675 }
676
677 if self.is_doc_hidden(attrs, defining_crate) { Visible::No } else { Visible::Yes }
678 }
679
680 pub(crate) fn is_doc_hidden(
681 &self,
682 attrs: &hir::AttrsWithOwner,
683 defining_crate: hir::Crate,
684 ) -> bool {
685 self.krate != defining_crate && attrs.is_doc_hidden()
687 }
688
689 pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec<SmolStr> {
690 if let Some(attrs) = scope_def.attrs(self.db) {
691 attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect()
692 } else {
693 vec![]
694 }
695 }
696}
697
698impl<'db> CompletionContext<'db> {
700 pub(crate) fn new(
701 db: &'db RootDatabase,
702 position @ FilePosition { file_id, offset }: FilePosition,
703 config: &'db CompletionConfig<'db>,
704 trigger_character: Option<char>,
705 ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
706 let _p = tracing::info_span!("CompletionContext::new").entered();
707 let sema = Semantics::new(db);
708
709 let editioned_file_id = sema.attach_first_edition(file_id);
710 let original_file = sema.parse(editioned_file_id);
711
712 let file_with_fake_ident = {
716 let (_, edition) = editioned_file_id.unpack(db);
717 let parse = db.parse(editioned_file_id);
718 parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, edition).tree()
719 };
720
721 let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
724
725 if original_token.kind() == T![:] {
728 let prev_token = original_token.prev_token()?;
730
731 if prev_token.kind() != T![:] {
733 return None;
734 }
735
736 if prev_token
740 .prev_token()
741 .map(|t| t.kind() == T![:] || t.kind() == T![::])
742 .unwrap_or(false)
743 {
744 return None;
745 }
746 }
747
748 let AnalysisResult {
749 analysis,
750 expected: (expected_type, expected_name),
751 qualifier_ctx,
752 token,
753 original_offset,
754 } = expand_and_analyze(
755 &sema,
756 InFile::new(editioned_file_id.into(), original_file.syntax().clone()),
757 file_with_fake_ident.syntax().clone(),
758 offset,
759 &original_token,
760 )?;
761
762 let scope = sema.scope_at_offset(&token.parent()?, original_offset)?;
764
765 let krate = scope.krate();
766 let module = scope.module();
767 let containing_function = scope.containing_function();
768 let edition = krate.edition(db);
769
770 let toolchain = db.toolchain_channel(krate.into());
771 let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
774
775 let mut locals = FxHashMap::default();
776 scope.process_all_names(&mut |name, scope| {
777 if let ScopeDef::Local(local) = scope {
778 if name.as_str().starts_with('<') {
781 return;
782 }
783 locals.insert(name, local);
784 }
785 });
786
787 let depth_from_crate_root = iter::successors(Some(module), |m| m.parent(db))
788 .filter(|m| !matches!(m.definition_source(db).value, ModuleSource::BlockExpr(_)))
790 .count()
791 .saturating_sub(1);
793
794 let exclude_traits: FxHashSet<_> = config
795 .exclude_traits
796 .iter()
797 .filter_map(|path| {
798 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern)).find_map(
799 |it| match it {
800 hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
801 _ => None,
802 },
803 )
804 })
805 .collect();
806
807 let mut exclude_flyimport: FxHashMap<_, _> = config
808 .exclude_flyimport
809 .iter()
810 .flat_map(|(path, kind)| {
811 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern))
812 .map(|it| (it.into_module_def(), *kind))
813 })
814 .collect();
815 exclude_flyimport
816 .extend(exclude_traits.iter().map(|&t| (t.into(), AutoImportExclusionType::Always)));
817
818 let complete_semicolon = if !config.add_semicolon_to_unit {
820 CompleteSemicolon::DoNotComplete
821 } else if let Some(term_node) =
822 sema.token_ancestors_with_macros(token.clone()).find(|node| {
823 matches!(node.kind(), BLOCK_EXPR | MATCH_ARM | CLOSURE_EXPR | ARG_LIST | PAREN_EXPR)
824 })
825 {
826 let next_token = iter::successors(token.next_token(), |it| it.next_token())
827 .map(|it| it.kind())
828 .find(|kind| !kind.is_trivia());
829 match term_node.kind() {
830 MATCH_ARM if next_token != Some(T![,]) => CompleteSemicolon::CompleteComma,
831 BLOCK_EXPR if next_token != Some(T![;]) => CompleteSemicolon::CompleteSemi,
832 _ => CompleteSemicolon::DoNotComplete,
833 }
834 } else {
835 CompleteSemicolon::DoNotComplete
836 };
837
838 let display_target = krate.to_display_target(db);
839 let ctx = CompletionContext {
840 sema,
841 scope,
842 db,
843 config,
844 position,
845 trigger_character,
846 original_token,
847 token,
848 krate,
849 module,
850 containing_function,
851 is_nightly,
852 edition,
853 expected_name,
854 expected_type,
855 qualifier_ctx,
856 locals,
857 depth_from_crate_root,
858 exclude_flyimport,
859 exclude_traits,
860 complete_semicolon,
861 display_target,
862 };
863 Some((ctx, analysis))
864 }
865}
866
867const OP_TRAIT_LANG: &[hir::LangItem] = &[
868 hir::LangItem::AddAssign,
869 hir::LangItem::Add,
870 hir::LangItem::BitAndAssign,
871 hir::LangItem::BitAnd,
872 hir::LangItem::BitOrAssign,
873 hir::LangItem::BitOr,
874 hir::LangItem::BitXorAssign,
875 hir::LangItem::BitXor,
876 hir::LangItem::DerefMut,
877 hir::LangItem::Deref,
878 hir::LangItem::DivAssign,
879 hir::LangItem::Div,
880 hir::LangItem::PartialEq,
881 hir::LangItem::FnMut,
882 hir::LangItem::FnOnce,
883 hir::LangItem::Fn,
884 hir::LangItem::IndexMut,
885 hir::LangItem::Index,
886 hir::LangItem::MulAssign,
887 hir::LangItem::Mul,
888 hir::LangItem::Neg,
889 hir::LangItem::Not,
890 hir::LangItem::PartialOrd,
891 hir::LangItem::RemAssign,
892 hir::LangItem::Rem,
893 hir::LangItem::ShlAssign,
894 hir::LangItem::Shl,
895 hir::LangItem::ShrAssign,
896 hir::LangItem::Shr,
897 hir::LangItem::Sub,
898];