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, 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
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<Either<hir::SelfParam, hir::Param<'db>>>,
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 MacroSegment,
393}
394
395#[derive(Debug)]
397pub(crate) struct DotAccess<'db> {
398 pub(crate) receiver: Option<ast::Expr>,
399 pub(crate) receiver_ty: Option<TypeInfo<'db>>,
400 pub(crate) kind: DotAccessKind,
401 pub(crate) ctx: DotAccessExprCtx,
402}
403
404#[derive(Debug, Clone, Copy)]
405pub(crate) enum DotAccessKind {
406 Field {
407 receiver_is_ambiguous_float_literal: bool,
410 },
411 Method,
412}
413
414#[derive(Debug, Clone, Copy, PartialEq, Eq)]
415pub(crate) struct DotAccessExprCtx {
416 pub(crate) in_block_expr: bool,
417 pub(crate) in_breakable: Option<BreakableKind>,
418}
419
420#[derive(Copy, Clone, Debug, PartialEq, Eq)]
421pub(crate) enum BreakableKind {
422 Loop,
423 For,
424 While,
425 Block,
426}
427
428#[derive(Clone, Debug, PartialEq, Eq)]
429pub(crate) enum ParamKind {
430 Function(ast::Fn),
431 Closure(ast::ClosureExpr),
432}
433
434#[derive(Debug)]
437pub(crate) struct CompletionContext<'a> {
438 pub(crate) sema: Semantics<'a, RootDatabase>,
439 pub(crate) scope: SemanticsScope<'a>,
440 pub(crate) db: &'a RootDatabase,
441 pub(crate) config: &'a CompletionConfig<'a>,
442 pub(crate) position: FilePosition,
443
444 pub(crate) trigger_character: Option<char>,
445 pub(crate) original_token: SyntaxToken,
447 pub(crate) token: SyntaxToken,
449 pub(crate) krate: hir::Crate,
451 pub(crate) display_target: DisplayTarget,
452 pub(crate) module: hir::Module,
454 pub(crate) containing_function: Option<hir::Function>,
456 pub(crate) is_nightly: bool,
458 pub(crate) edition: Edition,
461
462 pub(crate) expected_name: Option<NameOrNameRef>,
465 pub(crate) expected_type: Option<Type<'a>>,
467
468 pub(crate) qualifier_ctx: QualifierCtx,
469
470 pub(crate) locals: FxHashMap<Name, Local>,
471
472 pub(crate) depth_from_crate_root: usize,
479
480 pub(crate) exclude_flyimport: FxHashMap<ModuleDef, AutoImportExclusionType>,
485 pub(crate) exclude_traits: FxHashSet<hir::Trait>,
490
491 pub(crate) complete_semicolon: CompleteSemicolon,
493}
494
495#[derive(Debug)]
496pub(crate) enum CompleteSemicolon {
497 DoNotComplete,
498 CompleteSemi,
499 CompleteComma,
500}
501
502impl CompletionContext<'_> {
503 pub(crate) fn source_range(&self) -> TextRange {
505 let kind = self.original_token.kind();
506 match kind {
507 CHAR => {
508 cov_mark::hit!(completes_if_lifetime_without_idents);
510 TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
511 }
512 LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
513 _ if kind.is_any_identifier() => self.original_token.text_range(),
515 _ => TextRange::empty(self.position.offset),
516 }
517 }
518
519 pub(crate) fn famous_defs(&self) -> FamousDefs<'_, '_> {
520 FamousDefs(&self.sema, self.krate)
521 }
522
523 pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible {
525 match item {
526 ScopeDef::ModuleDef(def) => match def {
527 hir::ModuleDef::Module(it) => self.is_visible(it),
528 hir::ModuleDef::Function(it) => self.is_visible(it),
529 hir::ModuleDef::Adt(it) => self.is_visible(it),
530 hir::ModuleDef::Variant(it) => self.is_visible(it),
531 hir::ModuleDef::Const(it) => self.is_visible(it),
532 hir::ModuleDef::Static(it) => self.is_visible(it),
533 hir::ModuleDef::Trait(it) => self.is_visible(it),
534 hir::ModuleDef::TypeAlias(it) => self.is_visible(it),
535 hir::ModuleDef::Macro(it) => self.is_visible(it),
536 hir::ModuleDef::BuiltinType(_) => Visible::Yes,
537 },
538 ScopeDef::GenericParam(_)
539 | ScopeDef::ImplSelfType(_)
540 | ScopeDef::AdtSelfType(_)
541 | ScopeDef::Local(_)
542 | ScopeDef::Label(_)
543 | ScopeDef::Unknown => Visible::Yes,
544 }
545 }
546
547 pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
549 where
550 I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
551 {
552 let vis = item.visibility(self.db);
553 let attrs = item.attrs(self.db);
554 self.is_visible_impl(&vis, &attrs, item.krate(self.db))
555 }
556
557 pub(crate) fn doc_aliases<I>(&self, item: &I) -> Vec<SmolStr>
558 where
559 I: hir::HasAttrs + Copy,
560 {
561 let attrs = item.attrs(self.db);
562 attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect()
563 }
564
565 pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool {
567 let attrs = item.attrs(self.db);
568 let krate = item.krate(self.db);
569 match (attrs, krate) {
570 (Some(attrs), Some(krate)) => self.is_doc_hidden(&attrs, krate),
571 _ => false,
572 }
573 }
574
575 pub(crate) fn check_stability(&self, attrs: Option<&hir::AttrsWithOwner>) -> bool {
577 let Some(attrs) = attrs else {
578 return true;
579 };
580 !attrs.is_unstable() || self.is_nightly
581 }
582
583 pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
584 where
585 I: hir::HasAttrs + hir::HasCrate,
586 {
587 let defining_crate = item.krate(self.db);
588 let attrs = item.attrs(self.db);
589 self.check_stability(Some(&attrs)) && !self.is_doc_hidden(&attrs, defining_crate)
590 }
591
592 pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
594 match trait_.attrs(self.db).lang(self.db) {
595 Some(lang) => OP_TRAIT_LANG.contains(&lang),
596 None => false,
597 }
598 }
599
600 pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool {
602 trait_.attrs(self.db).is_doc_notable_trait()
603 }
604
605 pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
607 let mut traits_in_scope = self.scope.visible_traits();
608 if let Some(drop) = self.famous_defs().core_ops_Drop() {
609 traits_in_scope.0.remove(&drop.into());
610 }
611 traits_in_scope
612 }
613
614 pub(crate) fn iterate_path_candidates(
615 &self,
616 ty: &hir::Type<'_>,
617 mut cb: impl FnMut(hir::AssocItem),
618 ) {
619 let mut seen = FxHashSet::default();
620 ty.iterate_path_candidates(self.db, &self.scope, &self.traits_in_scope(), None, |item| {
621 if seen.insert(item) {
624 cb(item)
625 }
626 None::<()>
627 });
628 }
629
630 pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec<SmolStr>)) {
633 let _p = tracing::info_span!("CompletionContext::process_all_names").entered();
634 self.scope.process_all_names(&mut |name, def| {
635 if self.is_scope_def_hidden(def) {
636 return;
637 }
638 let doc_aliases = self.doc_aliases_in_scope(def);
639 f(name, def, doc_aliases);
640 });
641 }
642
643 pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
644 let _p = tracing::info_span!("CompletionContext::process_all_names_raw").entered();
645 self.scope.process_all_names(f);
646 }
647
648 fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
649 if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) {
650 return self.is_doc_hidden(&attrs, krate);
651 }
652
653 false
654 }
655
656 fn is_visible_impl(
657 &self,
658 vis: &hir::Visibility,
659 attrs: &hir::AttrsWithOwner,
660 defining_crate: hir::Crate,
661 ) -> Visible {
662 if !self.check_stability(Some(attrs)) {
663 return Visible::No;
664 }
665
666 if !vis.is_visible_from(self.db, self.module.into()) {
667 if !self.config.enable_private_editable {
668 return Visible::No;
669 }
670 return if is_editable_crate(defining_crate, self.db) {
672 Visible::Editable
673 } else {
674 Visible::No
675 };
676 }
677
678 if self.is_doc_hidden(attrs, defining_crate) { Visible::No } else { Visible::Yes }
679 }
680
681 pub(crate) fn is_doc_hidden(
682 &self,
683 attrs: &hir::AttrsWithOwner,
684 defining_crate: hir::Crate,
685 ) -> bool {
686 self.krate != defining_crate && attrs.is_doc_hidden()
688 }
689
690 pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec<SmolStr> {
691 if let Some(attrs) = scope_def.attrs(self.db) {
692 attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect()
693 } else {
694 vec![]
695 }
696 }
697}
698
699impl<'db> CompletionContext<'db> {
701 pub(crate) fn new(
702 db: &'db RootDatabase,
703 position @ FilePosition { file_id, offset }: FilePosition,
704 config: &'db CompletionConfig<'db>,
705 trigger_character: Option<char>,
706 ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
707 let _p = tracing::info_span!("CompletionContext::new").entered();
708 let sema = Semantics::new(db);
709
710 let editioned_file_id = sema.attach_first_edition(file_id);
711 let original_file = sema.parse(editioned_file_id);
712
713 let file_with_fake_ident = {
717 let (_, edition) = editioned_file_id.unpack(db);
718 let parse = db.parse(editioned_file_id);
719 parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, edition).tree()
720 };
721
722 let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
725
726 if original_token.kind() == T![:] {
729 let prev_token = original_token.prev_token()?;
731
732 if prev_token.kind() != T![:] && !is_in_macro_matcher(&original_token) {
734 return None;
735 }
736
737 if prev_token
741 .prev_token()
742 .map(|t| t.kind() == T![:] || t.kind() == T![::])
743 .unwrap_or(false)
744 {
745 return None;
746 }
747 }
748
749 let AnalysisResult {
750 analysis,
751 expected: (expected_type, expected_name),
752 qualifier_ctx,
753 token,
754 original_offset,
755 } = expand_and_analyze(
756 &sema,
757 InFile::new(editioned_file_id.into(), original_file.syntax().clone()),
758 file_with_fake_ident.syntax().clone(),
759 offset,
760 &original_token,
761 )?;
762
763 let scope = sema.scope_at_offset(&token.parent()?, original_offset)?;
765
766 let krate = scope.krate();
767 let module = scope.module();
768 let containing_function = scope.containing_function();
769 let edition = krate.edition(db);
770
771 let toolchain = db.toolchain_channel(krate.into());
772 let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
775
776 let mut locals = FxHashMap::default();
777 scope.process_all_names(&mut |name, scope| {
778 if let ScopeDef::Local(local) = scope {
779 if name.as_str().starts_with('<') {
782 return;
783 }
784 locals.insert(name, local);
785 }
786 });
787
788 let depth_from_crate_root = iter::successors(Some(module), |m| m.parent(db))
789 .filter(|m| !matches!(m.definition_source(db).value, ModuleSource::BlockExpr(_)))
791 .count()
792 .saturating_sub(1);
794
795 let exclude_traits: FxHashSet<_> = config
796 .exclude_traits
797 .iter()
798 .filter_map(|path| {
799 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern)).find_map(
800 |it| match it {
801 hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
802 _ => None,
803 },
804 )
805 })
806 .collect();
807
808 let mut exclude_flyimport: FxHashMap<_, _> = config
809 .exclude_flyimport
810 .iter()
811 .flat_map(|(path, kind)| {
812 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern))
813 .map(|it| (it.into_module_def(), *kind))
814 })
815 .collect();
816 exclude_flyimport
817 .extend(exclude_traits.iter().map(|&t| (t.into(), AutoImportExclusionType::Always)));
818
819 let complete_semicolon = if !config.add_semicolon_to_unit {
821 CompleteSemicolon::DoNotComplete
822 } else if let Some(term_node) =
823 sema.token_ancestors_with_macros(token.clone()).find(|node| {
824 matches!(node.kind(), BLOCK_EXPR | MATCH_ARM | CLOSURE_EXPR | ARG_LIST | PAREN_EXPR)
825 })
826 {
827 let next_token = iter::successors(token.next_token(), |it| it.next_token())
828 .map(|it| it.kind())
829 .find(|kind| !kind.is_trivia());
830 match term_node.kind() {
831 MATCH_ARM if next_token != Some(T![,]) => CompleteSemicolon::CompleteComma,
832 BLOCK_EXPR if next_token != Some(T![;]) => CompleteSemicolon::CompleteSemi,
833 _ => CompleteSemicolon::DoNotComplete,
834 }
835 } else {
836 CompleteSemicolon::DoNotComplete
837 };
838
839 let display_target = krate.to_display_target(db);
840 let ctx = CompletionContext {
841 sema,
842 scope,
843 db,
844 config,
845 position,
846 trigger_character,
847 original_token,
848 token,
849 krate,
850 module,
851 containing_function,
852 is_nightly,
853 edition,
854 expected_name,
855 expected_type,
856 qualifier_ctx,
857 locals,
858 depth_from_crate_root,
859 exclude_flyimport,
860 exclude_traits,
861 complete_semicolon,
862 display_target,
863 };
864 Some((ctx, analysis))
865 }
866}
867
868const OP_TRAIT_LANG: &[hir::LangItem] = &[
869 hir::LangItem::AddAssign,
870 hir::LangItem::Add,
871 hir::LangItem::BitAndAssign,
872 hir::LangItem::BitAnd,
873 hir::LangItem::BitOrAssign,
874 hir::LangItem::BitOr,
875 hir::LangItem::BitXorAssign,
876 hir::LangItem::BitXor,
877 hir::LangItem::DerefMut,
878 hir::LangItem::Deref,
879 hir::LangItem::DivAssign,
880 hir::LangItem::Div,
881 hir::LangItem::PartialEq,
882 hir::LangItem::FnMut,
883 hir::LangItem::FnOnce,
884 hir::LangItem::Fn,
885 hir::LangItem::IndexMut,
886 hir::LangItem::Index,
887 hir::LangItem::MulAssign,
888 hir::LangItem::Mul,
889 hir::LangItem::Neg,
890 hir::LangItem::Not,
891 hir::LangItem::PartialOrd,
892 hir::LangItem::RemAssign,
893 hir::LangItem::Rem,
894 hir::LangItem::ShlAssign,
895 hir::LangItem::Shl,
896 hir::LangItem::ShrAssign,
897 hir::LangItem::Shr,
898 hir::LangItem::Sub,
899];