1mod analysis;
4#[cfg(test)]
5mod tests;
6
7use std::{iter, sync::LazyLock};
8
9use base_db::toolchain_channel;
10use hir::{
11 DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
12 ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo, sym,
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, 'db> {
462 pub(crate) sema: Semantics<'db, RootDatabase>,
463 pub(crate) scope: SemanticsScope<'db>,
464 pub(crate) db: &'db 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<'db>>,
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<'db> CompletionContext<'_, 'db> {
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<'_, 'db> {
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 if !attrs.is_unstable() {
605 return true;
606 }
607 if !self.is_nightly {
608 return false;
609 }
610 let Some(unstable_feature) = attrs.unstable_feature(self.db) else {
612 return true;
613 };
614 !INTERNAL_FEATURES.contains(&unstable_feature)
615 || self.krate.is_unstable_feature_enabled(self.db, &unstable_feature)
616 }
617
618 pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
619 where
620 I: hir::HasAttrs + hir::HasCrate,
621 {
622 let defining_crate = item.krate(self.db);
623 let attrs = item.attrs(self.db);
624 self.check_stability(Some(&attrs)) && !self.is_doc_hidden(&attrs, defining_crate)
625 }
626
627 pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
629 match trait_.attrs(self.db).lang(self.db) {
630 Some(lang) => OP_TRAIT_LANG.contains(&lang),
631 None => false,
632 }
633 }
634
635 pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool {
637 trait_.attrs(self.db).is_doc_notable_trait()
638 }
639
640 pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
642 let mut traits_in_scope = self.scope.visible_traits();
643 if let Some(drop) = self.famous_defs().core_ops_Drop() {
644 traits_in_scope.0.remove(&drop.into());
645 }
646 traits_in_scope
647 }
648
649 pub(crate) fn iterate_path_candidates(
650 &self,
651 ty: &hir::Type<'_>,
652 mut cb: impl FnMut(hir::AssocItem),
653 ) {
654 let mut seen = FxHashSet::default();
655 ty.iterate_path_candidates(self.db, &self.scope, &self.traits_in_scope(), None, |item| {
656 if seen.insert(item) {
659 cb(item)
660 }
661 None::<()>
662 });
663 }
664
665 pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec<SmolStr>)) {
668 let _p = tracing::info_span!("CompletionContext::process_all_names").entered();
669 self.scope.process_all_names(&mut |name, def| {
670 if self.is_scope_def_hidden(def) {
671 return;
672 }
673 let doc_aliases = self.doc_aliases_in_scope(def);
674 f(name, def, doc_aliases);
675 });
676 }
677
678 pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
679 let _p = tracing::info_span!("CompletionContext::process_all_names_raw").entered();
680 self.scope.process_all_names(f);
681 }
682
683 fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
684 if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) {
685 return self.is_doc_hidden(&attrs, krate);
686 }
687
688 false
689 }
690
691 fn is_visible_impl(
692 &self,
693 vis: &hir::Visibility,
694 attrs: &hir::AttrsWithOwner,
695 defining_crate: hir::Crate,
696 ) -> Visible {
697 if !self.check_stability(Some(attrs)) {
698 return Visible::No;
699 }
700
701 if !vis.is_visible_from(self.db, self.module.into()) {
702 if !self.config.enable_private_editable {
703 return Visible::No;
704 }
705 return if is_editable_crate(defining_crate, self.db) {
707 Visible::Editable
708 } else {
709 Visible::No
710 };
711 }
712
713 if self.is_doc_hidden(attrs, defining_crate) { Visible::No } else { Visible::Yes }
714 }
715
716 pub(crate) fn is_doc_hidden(
717 &self,
718 attrs: &hir::AttrsWithOwner,
719 defining_crate: hir::Crate,
720 ) -> bool {
721 self.krate != defining_crate && attrs.is_doc_hidden()
723 }
724
725 pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec<SmolStr> {
726 if let Some(attrs) = scope_def.attrs(self.db) {
727 attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect()
728 } else {
729 vec![]
730 }
731 }
732}
733
734impl<'a, 'db> CompletionContext<'a, 'db> {
736 pub(crate) fn new(
737 db: &'db RootDatabase,
738 position @ FilePosition { file_id, offset }: FilePosition,
739 config: &'a CompletionConfig<'a>,
740 trigger_character: Option<char>,
741 ) -> Option<(CompletionContext<'a, 'db>, CompletionAnalysis<'db>)> {
742 let _p = tracing::info_span!("CompletionContext::new").entered();
743 let sema = Semantics::new(db);
744
745 let editioned_file_id = sema.attach_first_edition(file_id);
746 let original_file = sema.parse(editioned_file_id);
747
748 let file_with_fake_ident = {
752 let (_, edition) = editioned_file_id.unpack(db);
753 let parse = editioned_file_id.parse(db);
754 parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, edition).tree()
755 };
756
757 let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
760
761 if original_token.kind() == T![:] {
764 let prev_token = original_token.prev_token()?;
766
767 if prev_token.kind() != T![:] && !is_in_macro_matcher(&original_token) {
769 return None;
770 }
771
772 if prev_token
776 .prev_token()
777 .map(|t| t.kind() == T![:] || t.kind() == T![::])
778 .unwrap_or(false)
779 {
780 return None;
781 }
782 }
783
784 let AnalysisResult {
785 analysis,
786 expected: (expected_type, expected_name),
787 qualifier_ctx,
788 token,
789 original_offset,
790 } = expand_and_analyze(
791 &sema,
792 InFile::new(editioned_file_id.into(), original_file.syntax().clone()),
793 file_with_fake_ident.syntax().clone(),
794 offset,
795 &original_token,
796 )?;
797
798 let scope = sema.scope_at_offset(&token.parent()?, original_offset)?;
800
801 let krate = scope.krate();
802 let module = scope.module();
803 let containing_function = scope.containing_function();
804 let edition = krate.edition(db);
805
806 let toolchain = toolchain_channel(db, krate.into());
807 let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
810
811 let mut locals = FxHashMap::default();
812 scope.process_all_names(&mut |name, scope| {
813 if let ScopeDef::Local(local) = scope {
814 if name.as_str().starts_with('<') {
817 return;
818 }
819 locals.insert(name, local);
820 }
821 });
822
823 let depth_from_crate_root = iter::successors(Some(module), |m| m.parent(db))
824 .filter(|m| !matches!(m.definition_source(db).value, ModuleSource::BlockExpr(_)))
826 .count()
827 .saturating_sub(1);
829
830 let exclude_traits: FxHashSet<_> = config
831 .exclude_traits
832 .iter()
833 .filter_map(|path| {
834 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern)).find_map(
835 |it| match it {
836 hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
837 _ => None,
838 },
839 )
840 })
841 .collect();
842
843 let mut exclude_flyimport: FxHashMap<_, _> = config
844 .exclude_flyimport
845 .iter()
846 .flat_map(|(path, kind)| {
847 hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern))
848 .map(|it| (it.into_module_def(), *kind))
849 })
850 .collect();
851 exclude_flyimport
852 .extend(exclude_traits.iter().map(|&t| (t.into(), AutoImportExclusionType::Always)));
853
854 let complete_semicolon = if !config.add_semicolon_to_unit {
856 CompleteSemicolon::DoNotComplete
857 } else if let Some(term_node) =
858 sema.token_ancestors_with_macros(token.clone()).find(|node| {
859 matches!(
860 node.kind(),
861 BLOCK_EXPR | MATCH_ARM | CLOSURE_EXPR | ARG_LIST | PAREN_EXPR | ARRAY_EXPR
862 )
863 })
864 {
865 let next_token = iter::successors(token.next_token(), |it| it.next_token())
866 .map(|it| it.kind())
867 .find(|kind| !kind.is_trivia());
868 match term_node.kind() {
869 MATCH_ARM if next_token != Some(T![,]) => CompleteSemicolon::CompleteComma,
870 BLOCK_EXPR if next_token != Some(T![;]) => CompleteSemicolon::CompleteSemi,
871 _ => CompleteSemicolon::DoNotComplete,
872 }
873 } else {
874 CompleteSemicolon::DoNotComplete
875 };
876
877 let display_target = krate.to_display_target(db);
878 let ctx = CompletionContext {
879 sema,
880 scope,
881 db,
882 config,
883 position,
884 trigger_character,
885 original_token,
886 token,
887 krate,
888 module,
889 containing_function,
890 is_nightly,
891 edition,
892 expected_name,
893 expected_type,
894 qualifier_ctx,
895 locals,
896 depth_from_crate_root,
897 exclude_flyimport,
898 exclude_traits,
899 complete_semicolon,
900 display_target,
901 };
902 Some((ctx, analysis))
903 }
904}
905
906const OP_TRAIT_LANG: &[hir::LangItem] = &[
907 hir::LangItem::AddAssign,
908 hir::LangItem::Add,
909 hir::LangItem::BitAndAssign,
910 hir::LangItem::BitAnd,
911 hir::LangItem::BitOrAssign,
912 hir::LangItem::BitOr,
913 hir::LangItem::BitXorAssign,
914 hir::LangItem::BitXor,
915 hir::LangItem::DerefMut,
916 hir::LangItem::Deref,
917 hir::LangItem::DivAssign,
918 hir::LangItem::Div,
919 hir::LangItem::PartialEq,
920 hir::LangItem::FnMut,
921 hir::LangItem::FnOnce,
922 hir::LangItem::Fn,
923 hir::LangItem::IndexMut,
924 hir::LangItem::Index,
925 hir::LangItem::MulAssign,
926 hir::LangItem::Mul,
927 hir::LangItem::Neg,
928 hir::LangItem::Not,
929 hir::LangItem::PartialOrd,
930 hir::LangItem::RemAssign,
931 hir::LangItem::Rem,
932 hir::LangItem::ShlAssign,
933 hir::LangItem::Shl,
934 hir::LangItem::ShrAssign,
935 hir::LangItem::Shr,
936 hir::LangItem::Sub,
937];
938
939const INTERNAL_FEATURES_LIST: &[Symbol] = &[
941 sym::abi_unadjusted,
942 sym::allocator_internals,
943 sym::allow_internal_unsafe,
944 sym::allow_internal_unstable,
945 sym::cfg_emscripten_wasm_eh,
946 sym::cfg_target_has_reliable_f16_f128,
947 sym::compiler_builtins,
948 sym::custom_mir,
949 sym::eii_internals,
950 sym::field_representing_type_raw,
951 sym::intrinsics,
952 sym::lang_items,
953 sym::link_cfg,
954 sym::more_maybe_bounds,
955 sym::negative_bounds,
956 sym::pattern_complexity_limit,
957 sym::prelude_import,
958 sym::profiler_runtime,
959 sym::rustc_attrs,
960 sym::staged_api,
961 sym::test_unstable_lint,
962 sym::builtin_syntax,
963 sym::link_llvm_intrinsics,
964 sym::needs_panic_runtime,
965 sym::panic_runtime,
966 sym::pattern_types,
967 sym::rustdoc_internals,
968 sym::contracts_internals,
969 sym::freeze_impls,
970 sym::unsized_fn_params,
971];
972
973static INTERNAL_FEATURES: LazyLock<FxHashSet<Symbol>> =
974 LazyLock::new(|| INTERNAL_FEATURES_LIST.iter().cloned().collect());