Merge pull request #19375 from ChayimFriedman2/do-not-complete

feat: Allow crate authors to control completion of their things
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index b251564..e1fe13f 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -12,7 +12,7 @@
     ConstId, ExternCrateId, FunctionId, HasModule, ImplId, ItemContainerId, ItemLoc, Lookup,
     Macro2Id, MacroRulesId, ProcMacroId, StaticId, TraitAliasId, TraitId, TypeAliasId,
     db::DefDatabase,
-    item_tree::{self, FnFlags, ModItem},
+    item_tree::{self, FnFlags, ModItem, StaticFlags},
     nameres::proc_macro::{ProcMacroKind, parse_macro_name_and_helper_attrs},
     path::ImportAlias,
     type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
@@ -27,9 +27,8 @@
     pub visibility: RawVisibility,
     pub abi: Option<Symbol>,
     pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
-    pub rustc_allow_incoherent_impl: bool,
     pub types_map: Arc<TypesMap>,
-    flags: FnFlags,
+    pub flags: FnFlags,
 }
 
 impl FunctionData {
@@ -72,7 +71,9 @@
         }
 
         let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
-        let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists();
+        if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
+            flags |= FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
+        }
         if flags.contains(FnFlags::HAS_UNSAFE_KW)
             && attrs.by_key(&sym::rustc_deprecated_safe_2024).exists()
         {
@@ -101,51 +102,65 @@
             legacy_const_generics_indices: attrs.rustc_legacy_const_generics(),
             types_map: func.types_map.clone(),
             flags,
-            rustc_allow_incoherent_impl,
         })
     }
 
+    #[inline]
     pub fn has_body(&self) -> bool {
         self.flags.contains(FnFlags::HAS_BODY)
     }
 
     /// True if the first param is `self`. This is relevant to decide whether this
     /// can be called as a method.
+    #[inline]
     pub fn has_self_param(&self) -> bool {
         self.flags.contains(FnFlags::HAS_SELF_PARAM)
     }
 
+    #[inline]
     pub fn is_default(&self) -> bool {
         self.flags.contains(FnFlags::HAS_DEFAULT_KW)
     }
 
+    #[inline]
     pub fn is_const(&self) -> bool {
         self.flags.contains(FnFlags::HAS_CONST_KW)
     }
 
+    #[inline]
     pub fn is_async(&self) -> bool {
         self.flags.contains(FnFlags::HAS_ASYNC_KW)
     }
 
+    #[inline]
     pub fn is_unsafe(&self) -> bool {
         self.flags.contains(FnFlags::HAS_UNSAFE_KW)
     }
 
+    #[inline]
     pub fn is_deprecated_safe_2024(&self) -> bool {
         self.flags.contains(FnFlags::DEPRECATED_SAFE_2024)
     }
 
+    #[inline]
     pub fn is_safe(&self) -> bool {
         self.flags.contains(FnFlags::HAS_SAFE_KW)
     }
 
+    #[inline]
     pub fn is_varargs(&self) -> bool {
         self.flags.contains(FnFlags::IS_VARARGS)
     }
 
+    #[inline]
     pub fn has_target_feature(&self) -> bool {
         self.flags.contains(FnFlags::HAS_TARGET_FEATURE)
     }
+
+    #[inline]
+    pub fn rustc_allow_incoherent_impl(&self) -> bool {
+        self.flags.contains(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL)
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -153,15 +168,37 @@
     pub name: Name,
     pub type_ref: Option<TypeRefId>,
     pub visibility: RawVisibility,
-    pub is_extern: bool,
-    pub rustc_has_incoherent_inherent_impls: bool,
-    pub rustc_allow_incoherent_impl: bool,
+    pub flags: TypeAliasFlags,
     /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
     pub bounds: Box<[TypeBound]>,
     pub types_map: Arc<TypesMap>,
 }
 
+bitflags::bitflags! {
+    #[derive(Debug, Clone, PartialEq, Eq)]
+    pub struct TypeAliasFlags: u8 {
+        const IS_EXTERN = 1 << 0;
+        const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1;
+        const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 2;
+    }
+}
+
 impl TypeAliasData {
+    #[inline]
+    pub fn is_extern(&self) -> bool {
+        self.flags.contains(TypeAliasFlags::IS_EXTERN)
+    }
+
+    #[inline]
+    pub fn rustc_has_incoherent_inherent_impls(&self) -> bool {
+        self.flags.contains(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
+    }
+
+    #[inline]
+    pub fn rustc_allow_incoherent_impl(&self) -> bool {
+        self.flags.contains(TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPL)
+    }
+
     pub(crate) fn type_alias_data_query(
         db: &dyn DefDatabase,
         typ: TypeAliasId,
@@ -180,17 +217,24 @@
             loc.container.module(db).krate(),
             ModItem::from(loc.id.value).into(),
         );
-        let rustc_has_incoherent_inherent_impls =
-            attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists();
-        let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists();
+
+        let mut flags = TypeAliasFlags::empty();
+
+        if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
+            flags |= TypeAliasFlags::IS_EXTERN;
+        }
+        if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
+            flags |= TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
+        }
+        if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
+            flags |= TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
+        }
 
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
             type_ref: typ.type_ref,
             visibility,
-            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
-            rustc_has_incoherent_inherent_impls,
-            rustc_allow_incoherent_impl,
+            flags,
             bounds: typ.bounds.clone(),
             types_map: typ.types_map.clone(),
         })
@@ -199,7 +243,7 @@
 
 bitflags::bitflags! {
     #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
-    pub struct TraitFlags: u8 {
+    pub struct TraitFlags: u16 {
         const IS_AUTO = 1 << 0;
         const IS_UNSAFE = 1 << 1;
         const IS_FUNDAMENTAL = 1 << 2;
@@ -332,9 +376,9 @@
         let loc = makro.lookup(db);
         let item_tree = loc.id.item_tree(db);
         let makro = &item_tree[loc.id.value];
+        let attrs = item_tree.attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into());
 
-        let helpers = item_tree
-            .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
+        let helpers = attrs
             .by_key(&sym::rustc_builtin_macro)
             .tt_values()
             .next()
@@ -362,11 +406,9 @@
         let loc = makro.lookup(db);
         let item_tree = loc.id.item_tree(db);
         let makro = &item_tree[loc.id.value];
+        let attrs = item_tree.attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into());
 
-        let macro_export = item_tree
-            .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
-            .by_key(&sym::macro_export)
-            .exists();
+        let macro_export = attrs.by_key(&sym::macro_export).exists();
 
         Arc::new(MacroRulesData { name: makro.name.clone(), macro_export })
     }
@@ -387,11 +429,9 @@
         let loc = makro.lookup(db);
         let item_tree = loc.id.item_tree(db);
         let makro = &item_tree[loc.id.value];
+        let attrs = item_tree.attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into());
 
-        let (name, helpers) = if let Some(def) = item_tree
-            .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
-            .parse_proc_macro_decl(&makro.name)
-        {
+        let (name, helpers) = if let Some(def) = attrs.parse_proc_macro_decl(&makro.name) {
             (
                 def.name,
                 match def.kind {
@@ -404,6 +444,7 @@
             stdx::never!("proc macro declaration is not a proc macro");
             (makro.name.clone(), None)
         };
+
         Arc::new(ProcMacroData { name, helpers })
     }
 }
@@ -450,9 +491,16 @@
     pub name: Option<Name>,
     pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
-    pub rustc_allow_incoherent_impl: bool,
-    pub has_body: bool,
     pub types_map: Arc<TypesMap>,
+    pub flags: ConstFlags,
+}
+
+bitflags::bitflags! {
+    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+    pub struct ConstFlags: u8 {
+        const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 0;
+        const HAS_BODY = 1 << 1;
+    }
 }
 
 impl ConstData {
@@ -465,21 +513,38 @@
         } else {
             item_tree[konst.visibility].clone()
         };
+        let attrs = item_tree.attrs(
+            db,
+            loc.container.module(db).krate(),
+            ModItem::from(loc.id.value).into(),
+        );
 
-        let rustc_allow_incoherent_impl = item_tree
-            .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into())
-            .by_key(&sym::rustc_allow_incoherent_impl)
-            .exists();
+        let mut flags = ConstFlags::empty();
+        if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
+            flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
+        }
+        if konst.has_body {
+            flags |= ConstFlags::HAS_BODY;
+        }
 
         Arc::new(ConstData {
             name: konst.name.clone(),
             type_ref: konst.type_ref,
             visibility,
-            rustc_allow_incoherent_impl,
-            has_body: konst.has_body,
+            flags,
             types_map: konst.types_map.clone(),
         })
     }
+
+    #[inline]
+    pub fn rustc_allow_incoherent_impl(&self) -> bool {
+        self.flags.contains(ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL)
+    }
+
+    #[inline]
+    pub fn has_body(&self) -> bool {
+        self.flags.contains(ConstFlags::HAS_BODY)
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -487,11 +552,8 @@
     pub name: Name,
     pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
-    pub mutable: bool,
-    pub is_extern: bool,
-    pub has_safe_kw: bool,
-    pub has_unsafe_kw: bool,
     pub types_map: Arc<TypesMap>,
+    pub flags: StaticFlags,
 }
 
 impl StaticData {
@@ -500,17 +562,39 @@
         let item_tree = loc.id.item_tree(db);
         let statik = &item_tree[loc.id.value];
 
+        let mut flags = statik.flags;
+        if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
+            flags |= StaticFlags::IS_EXTERN;
+        }
+
         Arc::new(StaticData {
             name: statik.name.clone(),
             type_ref: statik.type_ref,
             visibility: item_tree[statik.visibility].clone(),
-            mutable: statik.mutable,
-            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
-            has_safe_kw: statik.has_safe_kw,
-            has_unsafe_kw: statik.has_unsafe_kw,
+            flags,
             types_map: statik.types_map.clone(),
         })
     }
+
+    #[inline]
+    pub fn is_extern(&self) -> bool {
+        self.flags.contains(StaticFlags::IS_EXTERN)
+    }
+
+    #[inline]
+    pub fn mutable(&self) -> bool {
+        self.flags.contains(StaticFlags::MUTABLE)
+    }
+
+    #[inline]
+    pub fn has_safe_kw(&self) -> bool {
+        self.flags.contains(StaticFlags::HAS_SAFE_KW)
+    }
+
+    #[inline]
+    pub fn has_unsafe_kw(&self) -> bool {
+        self.flags.contains(StaticFlags::HAS_UNSAFE_KW)
+    }
 }
 
 fn trait_vis(db: &dyn DefDatabase, trait_id: TraitId) -> RawVisibility {
diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs
index e470fe6..a54d766 100644
--- a/crates/hir-def/src/data/adt.rs
+++ b/crates/hir-def/src/data/adt.rs
@@ -226,6 +226,7 @@
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
         let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
         let mut flags = StructFlags::NO_FLAGS;
+
         if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
             flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
         }
@@ -290,10 +291,10 @@
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
-        let rustc_has_incoherent_inherent_impls = item_tree
-            .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
-            .by_key(&sym::rustc_has_incoherent_inherent_impls)
-            .exists();
+        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+
+        let rustc_has_incoherent_inherent_impls =
+            attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists();
 
         let enum_ = &item_tree[loc.id.value];
 
diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs
index 717566f..b1622ea 100644
--- a/crates/hir-def/src/import_map.rs
+++ b/crates/hir-def/src/import_map.rs
@@ -9,11 +9,11 @@
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use span::Edition;
-use stdx::{TupleExt, format_to};
+use stdx::format_to;
 use triomphe::Arc;
 
 use crate::{
-    AssocItemId, FxIndexMap, ModuleDefId, ModuleId, TraitId,
+    AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId,
     db::DefDatabase,
     item_scope::{ImportOrExternCrate, ItemInNs},
     nameres::DefMap,
@@ -31,6 +31,8 @@
     pub is_doc_hidden: bool,
     /// Whether this item is annotated with `#[unstable(..)]`.
     pub is_unstable: bool,
+    /// The value of `#[rust_analyzer::completions(...)]`, if exists.
+    pub complete: Complete,
 }
 
 /// A map from publicly exported items to its name.
@@ -172,16 +174,22 @@
                             ItemInNs::Macros(id) => Some(id.into()),
                         }
                     };
-                    let (is_doc_hidden, is_unstable) = attr_id.map_or((false, false), |attr_id| {
-                        let attrs = db.attrs(attr_id);
-                        (attrs.has_doc_hidden(), attrs.is_unstable())
-                    });
+                    let (is_doc_hidden, is_unstable, do_not_complete) = match attr_id {
+                        None => (false, false, Complete::Yes),
+                        Some(attr_id) => {
+                            let attrs = db.attrs(attr_id);
+                            let do_not_complete =
+                                Complete::extract(matches!(attr_id, AttrDefId::TraitId(_)), &attrs);
+                            (attrs.has_doc_hidden(), attrs.is_unstable(), do_not_complete)
+                        }
+                    };
 
                     let import_info = ImportInfo {
                         name: name.clone(),
                         container: module,
                         is_doc_hidden,
                         is_unstable,
+                        complete: do_not_complete,
                     };
 
                     if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
@@ -235,12 +243,17 @@
                 ItemInNs::Values(module_def_id)
             };
 
-            let attrs = &db.attrs(item.into());
+            let attr_id = item.into();
+            let attrs = &db.attrs(attr_id);
+            let item_do_not_complete = Complete::extract(false, attrs);
+            let do_not_complete =
+                Complete::for_trait_item(trait_import_info.complete, item_do_not_complete);
             let assoc_item_info = ImportInfo {
                 container: trait_import_info.container,
                 name: assoc_item_name.clone(),
                 is_doc_hidden: attrs.has_doc_hidden(),
                 is_unstable: attrs.is_unstable(),
+                complete: do_not_complete,
             };
 
             let (infos, _) =
@@ -398,7 +411,7 @@
     db: &dyn DefDatabase,
     krate: Crate,
     query: &Query,
-) -> FxHashSet<ItemInNs> {
+) -> FxHashSet<(ItemInNs, Complete)> {
     let _p = tracing::info_span!("search_dependencies", ?query).entered();
 
     let import_maps: Vec<_> =
@@ -439,7 +452,7 @@
     import_maps: &[Arc<ImportMap>],
     mut stream: fst::map::Union<'_>,
     query: &Query,
-) -> FxHashSet<ItemInNs> {
+) -> FxHashSet<(ItemInNs, Complete)> {
     let mut res = FxHashSet::default();
     while let Some((_, indexed_values)) = stream.next() {
         for &IndexedValue { index: import_map_idx, value } in indexed_values {
@@ -459,8 +472,9 @@
                 })
                 .filter(|&(_, info)| {
                     query.search_mode.check(&query.query, query.case_sensitive, info.name.as_str())
-                });
-            res.extend(iter.map(TupleExt::head));
+                })
+                .map(|(item, import_info)| (item, import_info.complete));
+            res.extend(iter);
         }
     }
 
@@ -521,7 +535,7 @@
 
         let actual = search_dependencies(db.upcast(), krate, &query)
             .into_iter()
-            .filter_map(|dependency| {
+            .filter_map(|(dependency, _)| {
                 let dependency_krate = dependency.krate(db.upcast())?;
                 let dependency_imports = db.import_map(dependency_krate);
 
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 47ad020..a299cfb 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -358,7 +358,7 @@
     }
 
     /// Get a name from current module scope, legacy macros are not included
-    pub(crate) fn get(&self, name: &Name) -> PerNs {
+    pub fn get(&self, name: &Name) -> PerNs {
         PerNs {
             types: self.types.get(name).copied(),
             values: self.values.get(name).copied(),
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 80d666a..1cabb66 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -962,7 +962,7 @@
 
 bitflags::bitflags! {
     #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
-    pub(crate) struct FnFlags: u16 {
+    pub struct FnFlags: u16 {
         const HAS_SELF_PARAM = 1 << 0;
         const HAS_BODY = 1 << 1;
         const HAS_DEFAULT_KW = 1 << 2;
@@ -977,6 +977,7 @@
         /// it if needed.
         const HAS_TARGET_FEATURE = 1 << 8;
         const DEPRECATED_SAFE_2024 = 1 << 9;
+        const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 10;
     }
 }
 
@@ -1050,15 +1051,22 @@
 pub struct Static {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    // TODO: use bitflags when we have more flags
-    pub mutable: bool,
-    pub has_safe_kw: bool,
-    pub has_unsafe_kw: bool,
+    pub flags: StaticFlags,
     pub type_ref: TypeRefId,
     pub ast_id: FileAstId<ast::Static>,
     pub types_map: Arc<TypesMap>,
 }
 
+bitflags::bitflags! {
+    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+    pub struct StaticFlags: u8 {
+        const MUTABLE = 1 << 0;
+        const IS_EXTERN = 1 << 1;
+        const HAS_SAFE_KW = 1 << 2;
+        const HAS_UNSAFE_KW = 1 << 3;
+    }
+}
+
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Trait {
     pub name: Name,
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index 5389ba4..4a3deec 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -29,8 +29,8 @@
         GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
         ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem,
         ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId,
-        Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
-        Variant,
+        Static, StaticFlags, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree,
+        UseTreeKind, Variant,
     },
     lower::LowerCtx,
     path::AssociatedTypeBinding,
@@ -620,22 +620,23 @@
         let name = static_.name()?.as_name();
         let type_ref = TypeRef::from_ast_opt(&mut body_ctx, static_.ty());
         let visibility = self.lower_visibility(static_);
-        let mutable = static_.mut_token().is_some();
-        let has_safe_kw = static_.safe_token().is_some();
-        let has_unsafe_kw = static_.unsafe_token().is_some();
+
+        let mut flags = StaticFlags::empty();
+        if static_.mut_token().is_some() {
+            flags |= StaticFlags::MUTABLE;
+        }
+        if static_.safe_token().is_some() {
+            flags |= StaticFlags::HAS_SAFE_KW;
+        }
+        if static_.unsafe_token().is_some() {
+            flags |= StaticFlags::HAS_UNSAFE_KW;
+        }
+
         let ast_id = self.source_ast_id_map.ast_id(static_);
         types_map.shrink_to_fit();
         types_source_map.shrink_to_fit();
-        let res = Static {
-            name,
-            visibility,
-            mutable,
-            type_ref,
-            ast_id,
-            has_safe_kw,
-            has_unsafe_kw,
-            types_map: Arc::new(types_map),
-        };
+        let res =
+            Static { name, visibility, type_ref, ast_id, flags, types_map: Arc::new(types_map) };
         self.source_maps.statics.push(types_source_map);
         Some(id(self.data().statics.alloc(res)))
     }
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index f44a000..b79b8a2 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -11,8 +11,8 @@
         AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
         FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
         ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
-        RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use,
-        UseTree, UseTreeKind, Variant,
+        RawVisibilityId, Static, StaticFlags, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
+        Union, Use, UseTree, UseTreeKind, Variant,
     },
     pretty::{print_path, print_type_bounds, print_type_ref},
     type_ref::{TypeRefId, TypesMap},
@@ -418,26 +418,18 @@
                 wln!(self, " = _;");
             }
             ModItem::Static(it) => {
-                let Static {
-                    name,
-                    visibility,
-                    mutable,
-                    type_ref,
-                    ast_id,
-                    has_safe_kw,
-                    has_unsafe_kw,
-                    types_map,
-                } = &self.tree[it];
+                let Static { name, visibility, type_ref, ast_id, types_map, flags } =
+                    &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                if *has_safe_kw {
+                if flags.contains(StaticFlags::HAS_SAFE_KW) {
                     w!(self, "safe ");
                 }
-                if *has_unsafe_kw {
+                if flags.contains(StaticFlags::HAS_UNSAFE_KW) {
                     w!(self, "unsafe ");
                 }
                 w!(self, "static ");
-                if *mutable {
+                if flags.contains(StaticFlags::MUTABLE) {
                     w!(self, "mut ");
                 }
                 w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 4601960..ab897f4 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -53,7 +53,7 @@
 pub mod import_map;
 pub mod visibility;
 
-use intern::Interned;
+use intern::{Interned, sym};
 pub use rustc_abi as layout;
 use triomphe::Arc;
 
@@ -86,6 +86,7 @@
 pub use hir_expand::{Intern, Lookup, tt};
 
 use crate::{
+    attr::Attrs,
     builtin_type::BuiltinType,
     data::adt::VariantData,
     db::DefDatabase,
@@ -1502,3 +1503,81 @@
 
 #[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
 pub struct SyntheticSyntax;
+
+// Feature: Completions Attribute
+// Crate authors can opt their type out of completions in some cases.
+// This is done with the `#[rust_analyzer::completions(...)]` attribute.
+//
+// All completeable things support `#[rust_analyzer::completions(ignore_flyimport)]`,
+// which causes the thing to get excluded from flyimport completion. It will still
+// be completed when in scope. This is analogous to the setting `rust-analyzer.completion.autoimport.exclude`
+// with `"type": "always"`.
+//
+// In addition, traits support two more modes: `#[rust_analyzer::completions(ignore_flyimport_methods)]`,
+// which means the trait itself may still be flyimported but its methods won't, and
+// `#[rust_analyzer::completions(ignore_methods)]`, which means the methods won't be completed even when
+// the trait is in scope (but the trait itself may still be completed). The methods will still be completed
+// on `dyn Trait`, `impl Trait` or where the trait is specified in bounds. These modes correspond to
+// the settings `rust-analyzer.completion.autoimport.exclude` with `"type": "methods"` and
+// `rust-analyzer.completion.excludeTraits`, respectively.
+//
+// Malformed attributes will be ignored without warnings.
+//
+// Note that users have no way to override this attribute, so be careful and only include things
+// users definitely do not want to be completed!
+
+/// `#[rust_analyzer::completions(...)]` options.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Complete {
+    /// No `#[rust_analyzer::completions(...)]`.
+    Yes,
+    /// `#[rust_analyzer::completions(ignore_flyimport)]`.
+    IgnoreFlyimport,
+    /// `#[rust_analyzer::completions(ignore_flyimport_methods)]` (on a trait only).
+    IgnoreFlyimportMethods,
+    /// `#[rust_analyzer::completions(ignore_methods)]` (on a trait only).
+    IgnoreMethods,
+}
+
+impl Complete {
+    pub fn extract(is_trait: bool, attrs: &Attrs) -> Complete {
+        let mut do_not_complete = Complete::Yes;
+        for ra_attr in attrs.rust_analyzer_tool() {
+            let segments = ra_attr.path.segments();
+            if segments.len() != 2 {
+                continue;
+            }
+            let action = segments[1].symbol();
+            if *action == sym::completions {
+                match ra_attr.token_tree_value().map(|tt| tt.token_trees().flat_tokens()) {
+                    Some([tt::TokenTree::Leaf(tt::Leaf::Ident(ident))]) => {
+                        if ident.sym == sym::ignore_flyimport {
+                            do_not_complete = Complete::IgnoreFlyimport;
+                        } else if is_trait {
+                            if ident.sym == sym::ignore_methods {
+                                do_not_complete = Complete::IgnoreMethods;
+                            } else if ident.sym == sym::ignore_flyimport_methods {
+                                do_not_complete = Complete::IgnoreFlyimportMethods;
+                            }
+                        }
+                    }
+                    _ => {}
+                }
+            }
+        }
+        do_not_complete
+    }
+
+    #[inline]
+    pub fn for_trait_item(trait_attr: Complete, item_attr: Complete) -> Complete {
+        match (trait_attr, item_attr) {
+            (
+                Complete::IgnoreFlyimportMethods
+                | Complete::IgnoreFlyimport
+                | Complete::IgnoreMethods,
+                _,
+            ) => Complete::IgnoreFlyimport,
+            _ => item_attr,
+        }
+    }
+}
diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs
index ce0ffb1..5fb8e8e 100644
--- a/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -558,7 +558,7 @@
 
     fn validate_static(&mut self, static_id: StaticId) {
         let data = self.db.static_data(static_id);
-        if data.is_extern {
+        if data.is_extern() {
             cov_mark::hit!(extern_static_incorrect_case_ignored);
             return;
         }
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 562a9aa..b4fe417 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -362,9 +362,9 @@
             self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene);
         if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
             let static_data = self.db.static_data(id);
-            if static_data.mutable {
+            if static_data.mutable() {
                 self.on_unsafe_op(node, UnsafetyReason::MutableStatic);
-            } else if static_data.is_extern && !static_data.has_safe_kw {
+            } else if static_data.is_extern() && !static_data.has_safe_kw() {
                 self.on_unsafe_op(node, UnsafetyReason::ExternStatic);
             }
         }
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 9df8d9c..355a403 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1577,7 +1577,7 @@
     let mut ctx = TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, t.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let inner = if type_alias_data.is_extern {
+    let inner = if type_alias_data.is_extern() {
         TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
     } else {
         type_alias_data
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 10b8dd2..d7c2f00 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -401,7 +401,7 @@
         }
         &TyKind::Foreign(id) => {
             let alias = from_foreign_def_id(id);
-            Some(if db.type_alias_data(alias).rustc_has_incoherent_inherent_impls {
+            Some(if db.type_alias_data(alias).rustc_has_incoherent_inherent_impls() {
                 db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::ForeignType(id))
             } else {
                 smallvec![alias.module(db.upcast()).krate()]
@@ -843,9 +843,11 @@
         rustc_has_incoherent_inherent_impls
             && !items.items.is_empty()
             && items.items.iter().all(|&(_, assoc)| match assoc {
-                AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl,
-                AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl,
-                AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl,
+                AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl(),
+                AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl(),
+                AssocItemId::TypeAliasId(it) => {
+                    db.type_alias_data(it).rustc_allow_incoherent_impl()
+                }
             })
     }
 }
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index ee412dd..498d707 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -2756,7 +2756,7 @@
             return Ok(*o);
         };
         let static_data = self.db.static_data(st);
-        let result = if !static_data.is_extern {
+        let result = if !static_data.is_extern() {
             let konst = self.db.const_eval_static(st).map_err(|e| {
                 MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e))
             })?;
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index ec34fd8..673c336 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -739,7 +739,7 @@
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         let data = f.db.static_data(self.id);
         f.write_str("static ")?;
-        if data.mutable {
+        if data.mutable() {
             f.write_str("mut ")?;
         }
         write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 124cbd2..c5ed044 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -114,6 +114,7 @@
 pub use {
     cfg::{CfgAtom, CfgExpr, CfgOptions},
     hir_def::{
+        Complete,
         ImportPathConfig,
         attr::{AttrSourceMap, Attrs, AttrsWithOwner},
         data::adt::StructKind,
@@ -254,14 +255,17 @@
         self,
         db: &dyn DefDatabase,
         query: import_map::Query,
-    ) -> impl Iterator<Item = Either<ModuleDef, Macro>> {
+    ) -> impl Iterator<Item = (Either<ModuleDef, Macro>, Complete)> {
         let _p = tracing::info_span!("query_external_importables").entered();
-        import_map::search_dependencies(db, self.into(), &query).into_iter().map(|item| {
-            match ItemInNs::from(item) {
-                ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id),
-                ItemInNs::Macros(mac_id) => Either::Right(mac_id),
-            }
-        })
+        import_map::search_dependencies(db, self.into(), &query).into_iter().map(
+            |(item, do_not_complete)| {
+                let item = match ItemInNs::from(item) {
+                    ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id),
+                    ItemInNs::Macros(mac_id) => Either::Right(mac_id),
+                };
+                (item, do_not_complete)
+            },
+        )
     }
 
     pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
@@ -811,7 +815,7 @@
                 let items = &db.trait_items(trait_.into()).items;
                 let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
                     AssocItemId::FunctionId(it) => !db.function_data(it).has_body(),
-                    AssocItemId::ConstId(id) => !db.const_data(id).has_body,
+                    AssocItemId::ConstId(id) => !db.const_data(id).has_body(),
                     AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(),
                 });
                 impl_assoc_items_scratch.extend(db.impl_items(impl_def.id).items.iter().cloned());
@@ -2812,7 +2816,7 @@
     }
 
     pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
-        db.static_data(self.id).mutable
+        db.static_data(self.id).mutable()
     }
 
     pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
@@ -2932,6 +2936,11 @@
             .map(|it| it.as_ref().clone().into_boxed_slice())
             .unwrap_or_default()
     }
+
+    /// `#[rust_analyzer::completions(...)]` mode.
+    pub fn complete(self, db: &dyn HirDatabase) -> Complete {
+        Complete::extract(true, &self.attrs(db))
+    }
 }
 
 impl HasVisibility for Trait {
@@ -6359,3 +6368,48 @@
         self(item)
     }
 }
+
+pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
+    db: &'a dyn HirDatabase,
+    mut segments: I,
+) -> impl Iterator<Item = ItemInNs> + use<'a, I> {
+    segments
+        .next()
+        .into_iter()
+        .flat_map(move |crate_name| {
+            db.all_crates()
+                .iter()
+                .filter(|&krate| {
+                    krate
+                        .extra_data(db)
+                        .display_name
+                        .as_ref()
+                        .is_some_and(|name| *name.crate_name().symbol() == crate_name)
+                })
+                .filter_map(|&krate| {
+                    let segments = segments.clone();
+                    let mut def_map = db.crate_def_map(krate);
+                    let mut module = &def_map[DefMap::ROOT];
+                    let mut segments = segments.with_position().peekable();
+                    while let Some((_, segment)) = segments.next_if(|&(position, _)| {
+                        !matches!(position, itertools::Position::Last | itertools::Position::Only)
+                    }) {
+                        let res = module
+                            .scope
+                            .get(&Name::new_symbol_root(segment))
+                            .take_types()
+                            .and_then(|res| match res {
+                                ModuleDefId::ModuleId(it) => Some(it),
+                                _ => None,
+                            })?;
+                        def_map = res.def_map(db.upcast());
+                        module = &def_map[res.local_id];
+                    }
+                    let (_, item_name) = segments.next()?;
+                    let res = module.scope.get(&Name::new_symbol_root(item_name));
+                    Some(res.iter_items().map(|(item, _)| item.into()))
+                })
+                .collect::<Vec<_>>()
+        })
+        .flatten()
+}
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index ae70f6f..679f775 100644
--- a/crates/hir/src/symbols.rs
+++ b/crates/hir/src/symbols.rs
@@ -2,7 +2,7 @@
 
 use either::Either;
 use hir_def::{
-    AdtId, AssocItemId, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId,
+    AdtId, AssocItemId, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId,
     ModuleDefId, ModuleId, TraitId,
     db::DefDatabase,
     item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob},
@@ -34,6 +34,7 @@
     /// Whether this symbol is a doc alias for the original symbol.
     pub is_alias: bool,
     pub is_assoc: bool,
+    pub do_not_complete: Complete,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -122,35 +123,43 @@
             match def {
                 ModuleDefId::ModuleId(id) => this.push_module(id, name),
                 ModuleDefId::FunctionId(id) => {
-                    this.push_decl(id, name, false);
+                    this.push_decl(id, name, false, None);
                     this.collect_from_body(id, Some(name.clone()));
                 }
-                ModuleDefId::AdtId(AdtId::StructId(id)) => this.push_decl(id, name, false),
-                ModuleDefId::AdtId(AdtId::EnumId(id)) => this.push_decl(id, name, false),
-                ModuleDefId::AdtId(AdtId::UnionId(id)) => this.push_decl(id, name, false),
+                ModuleDefId::AdtId(AdtId::StructId(id)) => {
+                    this.push_decl(id, name, false, None);
+                }
+                ModuleDefId::AdtId(AdtId::EnumId(id)) => {
+                    this.push_decl(id, name, false, None);
+                }
+                ModuleDefId::AdtId(AdtId::UnionId(id)) => {
+                    this.push_decl(id, name, false, None);
+                }
                 ModuleDefId::ConstId(id) => {
-                    this.push_decl(id, name, false);
+                    this.push_decl(id, name, false, None);
                     this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::StaticId(id) => {
-                    this.push_decl(id, name, false);
+                    this.push_decl(id, name, false, None);
                     this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::TraitId(id) => {
-                    this.push_decl(id, name, false);
-                    this.collect_from_trait(id);
+                    let trait_do_not_complete = this.push_decl(id, name, false, None);
+                    this.collect_from_trait(id, trait_do_not_complete);
                 }
                 ModuleDefId::TraitAliasId(id) => {
-                    this.push_decl(id, name, false);
+                    this.push_decl(id, name, false, None);
                 }
                 ModuleDefId::TypeAliasId(id) => {
-                    this.push_decl(id, name, false);
+                    this.push_decl(id, name, false, None);
                 }
-                ModuleDefId::MacroId(id) => match id {
-                    MacroId::Macro2Id(id) => this.push_decl(id, name, false),
-                    MacroId::MacroRulesId(id) => this.push_decl(id, name, false),
-                    MacroId::ProcMacroId(id) => this.push_decl(id, name, false),
-                },
+                ModuleDefId::MacroId(id) => {
+                    match id {
+                        MacroId::Macro2Id(id) => this.push_decl(id, name, false, None),
+                        MacroId::MacroRulesId(id) => this.push_decl(id, name, false, None),
+                        MacroId::ProcMacroId(id) => this.push_decl(id, name, false, None),
+                    };
+                }
                 // Don't index these.
                 ModuleDefId::BuiltinType(_) => {}
                 ModuleDefId::EnumVariantId(_) => {}
@@ -194,6 +203,7 @@
                 loc: dec_loc,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Complete::Yes,
             });
         };
 
@@ -223,6 +233,7 @@
                     loc: dec_loc,
                     is_alias: false,
                     is_assoc: false,
+                    do_not_complete: Complete::Yes,
                 });
             };
 
@@ -281,10 +292,10 @@
             for &id in id {
                 if id.module(self.db.upcast()) == module_id {
                     match id {
-                        MacroId::Macro2Id(id) => self.push_decl(id, name, false),
-                        MacroId::MacroRulesId(id) => self.push_decl(id, name, false),
-                        MacroId::ProcMacroId(id) => self.push_decl(id, name, false),
-                    }
+                        MacroId::Macro2Id(id) => self.push_decl(id, name, false, None),
+                        MacroId::MacroRulesId(id) => self.push_decl(id, name, false, None),
+                        MacroId::ProcMacroId(id) => self.push_decl(id, name, false, None),
+                    };
                 }
             }
         }
@@ -314,16 +325,16 @@
         );
         self.with_container_name(impl_name, |s| {
             for &(ref name, assoc_item_id) in &self.db.impl_items(impl_id).items {
-                s.push_assoc_item(assoc_item_id, name)
+                s.push_assoc_item(assoc_item_id, name, None)
             }
         })
     }
 
-    fn collect_from_trait(&mut self, trait_id: TraitId) {
+    fn collect_from_trait(&mut self, trait_id: TraitId, trait_do_not_complete: Complete) {
         let trait_data = self.db.trait_data(trait_id);
         self.with_container_name(Some(trait_data.name.as_str().into()), |s| {
             for &(ref name, assoc_item_id) in &self.db.trait_items(trait_id).items {
-                s.push_assoc_item(assoc_item_id, name);
+                s.push_assoc_item(assoc_item_id, name, Some(trait_do_not_complete));
             }
         });
     }
@@ -338,15 +349,26 @@
         }
     }
 
-    fn push_assoc_item(&mut self, assoc_item_id: AssocItemId, name: &Name) {
+    fn push_assoc_item(
+        &mut self,
+        assoc_item_id: AssocItemId,
+        name: &Name,
+        trait_do_not_complete: Option<Complete>,
+    ) {
         match assoc_item_id {
-            AssocItemId::FunctionId(id) => self.push_decl(id, name, true),
-            AssocItemId::ConstId(id) => self.push_decl(id, name, true),
-            AssocItemId::TypeAliasId(id) => self.push_decl(id, name, true),
-        }
+            AssocItemId::FunctionId(id) => self.push_decl(id, name, true, trait_do_not_complete),
+            AssocItemId::ConstId(id) => self.push_decl(id, name, true, trait_do_not_complete),
+            AssocItemId::TypeAliasId(id) => self.push_decl(id, name, true, trait_do_not_complete),
+        };
     }
 
-    fn push_decl<L>(&mut self, id: L, name: &Name, is_assoc: bool)
+    fn push_decl<L>(
+        &mut self,
+        id: L,
+        name: &Name,
+        is_assoc: bool,
+        trait_do_not_complete: Option<Complete>,
+    ) -> Complete
     where
         L: Lookup<Database = dyn DefDatabase> + Into<ModuleDefId>,
         <L as Lookup>::Data: HasSource,
@@ -354,7 +376,7 @@
     {
         let loc = id.lookup(self.db.upcast());
         let source = loc.source(self.db.upcast());
-        let Some(name_node) = source.value.name() else { return };
+        let Some(name_node) = source.value.name() else { return Complete::Yes };
         let def = ModuleDef::from(id.into());
         let dec_loc = DeclarationLocation {
             hir_file_id: source.file_id,
@@ -362,7 +384,14 @@
             name_ptr: AstPtr::new(&name_node).wrap_left(),
         };
 
+        let mut do_not_complete = Complete::Yes;
+
         if let Some(attrs) = def.attrs(self.db) {
+            do_not_complete = Complete::extract(matches!(def, ModuleDef::Trait(_)), &attrs);
+            if let Some(trait_do_not_complete) = trait_do_not_complete {
+                do_not_complete = Complete::for_trait_item(trait_do_not_complete, do_not_complete);
+            }
+
             for alias in attrs.doc_aliases() {
                 self.symbols.insert(FileSymbol {
                     name: alias.clone(),
@@ -371,6 +400,7 @@
                     container_name: self.current_container_name.clone(),
                     is_alias: true,
                     is_assoc,
+                    do_not_complete,
                 });
             }
         }
@@ -382,7 +412,10 @@
             loc: dec_loc,
             is_alias: false,
             is_assoc,
+            do_not_complete,
         });
+
+        do_not_complete
     }
 
     fn push_module(&mut self, module_id: ModuleId, name: &Name) {
@@ -399,7 +432,10 @@
 
         let def = ModuleDef::Module(module_id.into());
 
+        let mut do_not_complete = Complete::Yes;
         if let Some(attrs) = def.attrs(self.db) {
+            do_not_complete = Complete::extract(matches!(def, ModuleDef::Trait(_)), &attrs);
+
             for alias in attrs.doc_aliases() {
                 self.symbols.insert(FileSymbol {
                     name: alias.clone(),
@@ -408,6 +444,7 @@
                     container_name: self.current_container_name.clone(),
                     is_alias: true,
                     is_assoc: false,
+                    do_not_complete,
                 });
             }
         }
@@ -419,6 +456,7 @@
             loc: dec_loc,
             is_alias: false,
             is_assoc: false,
+            do_not_complete,
         });
     }
 }
diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 691ae93..feeea88 100644
--- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -78,7 +78,7 @@
         NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
         items_locator::AssocSearchMode::Exclude,
     )
-    .filter_map(|item| match item.into_module_def() {
+    .filter_map(|(item, _)| match item.into_module_def() {
         ModuleDef::Trait(trait_) => Some(trait_),
         _ => None,
     })
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index dea983b..4f21136 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -2,7 +2,7 @@
 
 use std::ops::ControlFlow;
 
-use hir::{HasContainer, ItemContainer, MethodCandidateCallback, Name};
+use hir::{Complete, HasContainer, ItemContainer, MethodCandidateCallback, Name};
 use ide_db::FxHashSet;
 use syntax::SmolStr;
 
@@ -259,7 +259,9 @@
             // This needs to come before the `seen_methods` test, so that if we see the same method twice,
             // once as inherent and once not, we will include it.
             if let ItemContainer::Trait(trait_) = func.container(self.ctx.db) {
-                if self.ctx.exclude_traits.contains(&trait_) {
+                if self.ctx.exclude_traits.contains(&trait_)
+                    || trait_.complete(self.ctx.db) == Complete::IgnoreMethods
+                {
                     return ControlFlow::Continue(());
                 }
             }
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 7219a5f..0494d42 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -2,7 +2,7 @@
 
 use std::ops::ControlFlow;
 
-use hir::{Name, PathCandidateCallback, ScopeDef, sym};
+use hir::{Complete, Name, PathCandidateCallback, ScopeDef, sym};
 use ide_db::FxHashSet;
 use syntax::ast;
 
@@ -33,10 +33,10 @@
     fn on_trait_item(&mut self, item: hir::AssocItem) -> ControlFlow<()> {
         // The excluded check needs to come before the `seen` test, so that if we see the same method twice,
         // once as inherent and once not, we will include it.
-        if item
-            .container_trait(self.ctx.db)
-            .is_none_or(|trait_| !self.ctx.exclude_traits.contains(&trait_))
-            && self.seen.insert(item)
+        if item.container_trait(self.ctx.db).is_none_or(|trait_| {
+            !self.ctx.exclude_traits.contains(&trait_)
+                && trait_.complete(self.ctx.db) != Complete::IgnoreMethods
+        }) && self.seen.insert(item)
         {
             (self.add_assoc_item)(self.acc, item);
         }
@@ -104,7 +104,9 @@
             .iter()
             .copied()
             .map(hir::Trait::from)
-            .filter(|it| !ctx.exclude_traits.contains(it))
+            .filter(|it| {
+                !ctx.exclude_traits.contains(it) && it.complete(ctx.db) != Complete::IgnoreMethods
+            })
             .flat_map(|it| it.items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
         Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index b3ba076..a747561 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -268,19 +268,7 @@
                 && !ctx.is_item_hidden(original_item)
                 && ctx.check_stability(original_item.attrs(ctx.db).as_deref())
         })
-        .filter(|import| {
-            let def = import.item_to_import.into_module_def();
-            if let Some(&kind) = ctx.exclude_flyimport.get(&def) {
-                if kind == AutoImportExclusionType::Always {
-                    return false;
-                }
-                let method_imported = import.item_to_import != import.original_item;
-                if method_imported {
-                    return false;
-                }
-            }
-            true
-        })
+        .filter(|import| filter_excluded_flyimport(ctx, import))
         .sorted_by(|a, b| {
             let key = |import_path| {
                 (
@@ -366,24 +354,7 @@
             !ctx.is_item_hidden(&import.item_to_import)
                 && !ctx.is_item_hidden(&import.original_item)
         })
-        .filter(|import| {
-            let def = import.item_to_import.into_module_def();
-            if let Some(&kind) = ctx.exclude_flyimport.get(&def) {
-                if kind == AutoImportExclusionType::Always {
-                    return false;
-                }
-                let method_imported = import.item_to_import != import.original_item;
-                if method_imported {
-                    return false;
-                }
-            }
-
-            if let ModuleDef::Trait(_) = import.item_to_import.into_module_def() {
-                !ctx.exclude_flyimport.contains_key(&def)
-            } else {
-                true
-            }
-        })
+        .filter(|import| filter_excluded_flyimport(ctx, import))
         .sorted_by(|a, b| {
             let key = |import_path| {
                 (
@@ -401,6 +372,28 @@
     Some(())
 }
 
+fn filter_excluded_flyimport(ctx: &CompletionContext<'_>, import: &LocatedImport) -> bool {
+    let def = import.item_to_import.into_module_def();
+    let is_exclude_flyimport = ctx.exclude_flyimport.get(&def).copied();
+
+    if matches!(is_exclude_flyimport, Some(AutoImportExclusionType::Always))
+        || !import.complete_in_flyimport.0
+    {
+        return false;
+    }
+    let method_imported = import.item_to_import != import.original_item;
+    if method_imported
+        && (is_exclude_flyimport.is_some()
+            || ctx.exclude_flyimport.contains_key(&import.original_item.into_module_def()))
+    {
+        // If this is a method, exclude it either if it was excluded itself (which may not be caught above,
+        // because `item_to_import` is the trait), or if its trait was excluded. We don't need to check
+        // the attributes here, since they pass from trait to methods on import map construction.
+        return false;
+    }
+    true
+}
+
 fn import_name(ctx: &CompletionContext<'_>) -> String {
     let token_kind = ctx.token.kind();
 
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 3043796..fd25ee0 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -8,8 +8,8 @@
 
 use base_db::{RootQueryDb as _, salsa::AsDynDatabase};
 use hir::{
-    DisplayTarget, HasAttrs, Local, ModPath, ModuleDef, ModuleSource, Name, PathResolution,
-    ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
+    DisplayTarget, HasAttrs, Local, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef,
+    Semantics, SemanticsScope, Symbol, Type, TypeInfo,
 };
 use ide_db::{
     FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
@@ -796,15 +796,12 @@
             .exclude_traits
             .iter()
             .filter_map(|path| {
-                scope
-                    .resolve_mod_path(&ModPath::from_segments(
-                        hir::PathKind::Plain,
-                        path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
-                    ))
-                    .find_map(|it| match it {
+                hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern)).find_map(
+                    |it| match it {
                         hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
                         _ => None,
-                    })
+                    },
+                )
             })
             .collect();
 
@@ -812,11 +809,7 @@
             .exclude_flyimport
             .iter()
             .flat_map(|(path, kind)| {
-                scope
-                    .resolve_mod_path(&ModPath::from_segments(
-                        hir::PathKind::Plain,
-                        path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
-                    ))
+                hir::resolve_absolute_path(db, path.split("::").map(Symbol::intern))
                     .map(|it| (it.into_module_def(), *kind))
             })
             .collect();
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 82c1266..b0adbad 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -334,7 +334,7 @@
             continue;
         };
 
-        item.add_import(LocatedImport::new(path, trait_item, trait_item));
+        item.add_import(LocatedImport::new_no_completion(path, trait_item, trait_item));
     }
 
     Some(item)
diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs
index 07f33a8..9dc0c02 100644
--- a/crates/ide-completion/src/snippet.rs
+++ b/crates/ide-completion/src/snippet.rs
@@ -174,7 +174,7 @@
             ctx.config.insert_use.prefix_kind,
             import_cfg,
         )?;
-        Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item)))
+        Some((path.len() > 1).then(|| LocatedImport::new_no_completion(path.clone(), item, item)))
     };
     let mut res = Vec::with_capacity(requires.len());
     for import in requires {
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 22d42ba..98da2cb 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -1555,7 +1555,10 @@
 #[test]
 fn excluded_trait_method_is_excluded() {
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 trait ExcludedTrait {
     fn foo(&self) {}
@@ -1575,23 +1578,20 @@
 }
         "#,
         expect![[r#"
-            me bar() (as ExcludedTrait) fn(&self)
-            me baz() (as ExcludedTrait) fn(&self)
-            me foo() (as ExcludedTrait) fn(&self)
-            me inherent()               fn(&self)
-            sn box                 Box::new(expr)
-            sn call                function(expr)
-            sn const                     const {}
-            sn dbg                     dbg!(expr)
-            sn dbgr                   dbg!(&expr)
-            sn deref                        *expr
-            sn let                            let
-            sn letm                       let mut
-            sn match                match expr {}
-            sn ref                          &expr
-            sn refm                     &mut expr
-            sn return                 return expr
-            sn unsafe                   unsafe {}
+            me inherent() fn(&self)
+            sn box   Box::new(expr)
+            sn call  function(expr)
+            sn const       const {}
+            sn dbg       dbg!(expr)
+            sn dbgr     dbg!(&expr)
+            sn deref          *expr
+            sn let              let
+            sn letm         let mut
+            sn match  match expr {}
+            sn ref            &expr
+            sn refm       &mut expr
+            sn return   return expr
+            sn unsafe     unsafe {}
         "#]],
     );
 }
@@ -1599,7 +1599,10 @@
 #[test]
 fn excluded_trait_not_excluded_when_inherent() {
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 trait ExcludedTrait {
     fn foo(&self) {}
@@ -1633,7 +1636,10 @@
         "#]],
     );
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 trait ExcludedTrait {
     fn foo(&self) {}
@@ -1667,7 +1673,10 @@
         "#]],
     );
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 trait ExcludedTrait {
     fn foo(&self) {}
@@ -1706,7 +1715,7 @@
 fn excluded_trait_method_is_excluded_from_flyimport() {
     check_with_config(
         CompletionConfig {
-            exclude_traits: &["test::module2::ExcludedTrait".to_owned()],
+            exclude_traits: &["ra_test_fixture::module2::ExcludedTrait".to_owned()],
             ..TEST_CONFIG
         },
         r#"
@@ -1730,23 +1739,20 @@
 }
         "#,
         expect![[r#"
-            me bar() (use module2::ExcludedTrait) fn(&self)
-            me baz() (use module2::ExcludedTrait) fn(&self)
-            me foo() (use module2::ExcludedTrait) fn(&self)
-            me inherent()                         fn(&self)
-            sn box                           Box::new(expr)
-            sn call                          function(expr)
-            sn const                               const {}
-            sn dbg                               dbg!(expr)
-            sn dbgr                             dbg!(&expr)
-            sn deref                                  *expr
-            sn let                                      let
-            sn letm                                 let mut
-            sn match                          match expr {}
-            sn ref                                    &expr
-            sn refm                               &mut expr
-            sn return                           return expr
-            sn unsafe                             unsafe {}
+            me inherent() fn(&self)
+            sn box   Box::new(expr)
+            sn call  function(expr)
+            sn const       const {}
+            sn dbg       dbg!(expr)
+            sn dbgr     dbg!(&expr)
+            sn deref          *expr
+            sn let              let
+            sn letm         let mut
+            sn match  match expr {}
+            sn ref            &expr
+            sn refm       &mut expr
+            sn return   return expr
+            sn unsafe     unsafe {}
         "#]],
     );
 }
@@ -1756,7 +1762,7 @@
     check_with_config(
         CompletionConfig {
             exclude_flyimport: vec![(
-                "test::module2::ExcludedTrait".to_owned(),
+                "ra_test_fixture::module2::ExcludedTrait".to_owned(),
                 AutoImportExclusionType::Methods,
             )],
             ..TEST_CONFIG
@@ -1782,23 +1788,20 @@
 }
         "#,
         expect![[r#"
-            me bar() (use module2::ExcludedTrait) fn(&self)
-            me baz() (use module2::ExcludedTrait) fn(&self)
-            me foo() (use module2::ExcludedTrait) fn(&self)
-            me inherent()                         fn(&self)
-            sn box                           Box::new(expr)
-            sn call                          function(expr)
-            sn const                               const {}
-            sn dbg                               dbg!(expr)
-            sn dbgr                             dbg!(&expr)
-            sn deref                                  *expr
-            sn let                                      let
-            sn letm                                 let mut
-            sn match                          match expr {}
-            sn ref                                    &expr
-            sn refm                               &mut expr
-            sn return                           return expr
-            sn unsafe                             unsafe {}
+            me inherent() fn(&self)
+            sn box   Box::new(expr)
+            sn call  function(expr)
+            sn const       const {}
+            sn dbg       dbg!(expr)
+            sn dbgr     dbg!(&expr)
+            sn deref          *expr
+            sn let              let
+            sn letm         let mut
+            sn match  match expr {}
+            sn ref            &expr
+            sn refm       &mut expr
+            sn return   return expr
+            sn unsafe     unsafe {}
         "#]],
     );
 }
@@ -1806,7 +1809,10 @@
 #[test]
 fn excluded_trait_method_is_excluded_from_path_completion() {
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 pub trait ExcludedTrait {
     fn foo(&self) {}
@@ -1826,10 +1832,7 @@
 }
         "#,
         expect![[r#"
-            me bar(…) (as ExcludedTrait) fn(&self)
-            me baz(…) (as ExcludedTrait) fn(&self)
-            me foo(…) (as ExcludedTrait) fn(&self)
-            me inherent(…)               fn(&self)
+            me inherent(…) fn(&self)
         "#]],
     );
 }
@@ -1837,7 +1840,10 @@
 #[test]
 fn excluded_trait_method_is_not_excluded_when_trait_is_specified() {
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 pub trait ExcludedTrait {
     fn foo(&self) {}
@@ -1863,7 +1869,10 @@
             "#]],
     );
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 pub trait ExcludedTrait {
     fn foo(&self) {}
@@ -1893,7 +1902,10 @@
 #[test]
 fn excluded_trait_not_excluded_when_inherent_path() {
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 trait ExcludedTrait {
     fn foo(&self) {}
@@ -1914,7 +1926,10 @@
         "#]],
     );
     check_with_config(
-        CompletionConfig { exclude_traits: &["test::ExcludedTrait".to_owned()], ..TEST_CONFIG },
+        CompletionConfig {
+            exclude_traits: &["ra_test_fixture::ExcludedTrait".to_owned()],
+            ..TEST_CONFIG
+        },
         r#"
 trait ExcludedTrait {
     fn foo(&self) {}
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 8bba44c..27c91bc 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -1810,9 +1810,10 @@
 
 #[test]
 fn excluded_trait_item_included_when_exact_match() {
+    // FIXME: This does not work, we need to change the code.
     check_with_config(
         CompletionConfig {
-            exclude_traits: &["test::module2::ExcludedTrait".to_owned()],
+            exclude_traits: &["ra_test_fixture::module2::ExcludedTrait".to_owned()],
             ..TEST_CONFIG
         },
         r#"
@@ -1830,8 +1831,120 @@
     true.foo$0
 }
         "#,
+        expect![""],
+    );
+}
+
+#[test]
+fn excluded_via_attr() {
+    check(
+        r#"
+mod module2 {
+    #[rust_analyzer::completions(ignore_flyimport)]
+    pub trait ExcludedTrait {
+        fn foo(&self) {}
+        fn bar(&self) {}
+        fn baz(&self) {}
+    }
+
+    impl<T> ExcludedTrait for T {}
+}
+
+fn foo() {
+    true.$0
+}
+        "#,
+        expect![""],
+    );
+    check(
+        r#"
+mod module2 {
+    #[rust_analyzer::completions(ignore_flyimport_methods)]
+    pub trait ExcludedTrait {
+        fn foo(&self) {}
+        fn bar(&self) {}
+        fn baz(&self) {}
+    }
+
+    impl<T> ExcludedTrait for T {}
+}
+
+fn foo() {
+    true.$0
+}
+        "#,
+        expect![""],
+    );
+    check(
+        r#"
+mod module2 {
+    #[rust_analyzer::completions(ignore_methods)]
+    pub trait ExcludedTrait {
+        fn foo(&self) {}
+        fn bar(&self) {}
+        fn baz(&self) {}
+    }
+
+    impl<T> ExcludedTrait for T {}
+}
+
+fn foo() {
+    true.$0
+}
+        "#,
+        expect![""],
+    );
+    check(
+        r#"
+mod module2 {
+    #[rust_analyzer::completions(ignore_flyimport)]
+    pub trait ExcludedTrait {
+        fn foo(&self) {}
+        fn bar(&self) {}
+        fn baz(&self) {}
+    }
+
+    impl<T> ExcludedTrait for T {}
+}
+
+fn foo() {
+    ExcludedTrait$0
+}
+        "#,
+        expect![""],
+    );
+    check(
+        r#"
+mod module2 {
+    #[rust_analyzer::completions(ignore_methods)]
+    pub trait ExcludedTrait {
+        fn foo(&self) {}
+        fn bar(&self) {}
+        fn baz(&self) {}
+    }
+
+    impl<T> ExcludedTrait for T {}
+}
+
+fn foo() {
+    ExcludedTrait$0
+}
+        "#,
         expect![[r#"
-            me foo() (use module2::ExcludedTrait) fn(&self)
+            tt ExcludedTrait (use module2::ExcludedTrait)
         "#]],
     );
+    check(
+        r#"
+mod module2 {
+    #[rust_analyzer::completions(ignore_flyimport)]
+    pub struct Foo {}
+}
+
+fn foo() {
+    Foo$0
+}
+        "#,
+        expect![""],
+    );
 }
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 650c957..ac592df 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -3,8 +3,8 @@
 use std::ops::ControlFlow;
 
 use hir::{
-    AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig, ItemInNs,
-    ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
+    AsAssocItem, AssocItem, AssocItemContainer, Complete, Crate, HasCrate, ImportPathConfig,
+    ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
     SemanticsScope, Trait, TyFingerprint, Type, db::HirDatabase,
 };
 use itertools::Itertools;
@@ -183,6 +183,9 @@
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CompleteInFlyimport(pub bool);
+
 /// An import (not necessary the only one) that corresponds a certain given [`PathImportCandidate`].
 /// (the structure is not entirely correct, since there can be situations requiring two imports, see FIXME below for the details)
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -198,11 +201,31 @@
     /// the original item is the associated constant, but the import has to be a trait that
     /// defines this constant.
     pub original_item: ItemInNs,
+    /// The value of `#[rust_analyzer::completions(...)]`, if existing.
+    pub complete_in_flyimport: CompleteInFlyimport,
 }
 
 impl LocatedImport {
-    pub fn new(import_path: ModPath, item_to_import: ItemInNs, original_item: ItemInNs) -> Self {
-        Self { import_path, item_to_import, original_item }
+    pub fn new(
+        import_path: ModPath,
+        item_to_import: ItemInNs,
+        original_item: ItemInNs,
+        complete_in_flyimport: CompleteInFlyimport,
+    ) -> Self {
+        Self { import_path, item_to_import, original_item, complete_in_flyimport }
+    }
+
+    pub fn new_no_completion(
+        import_path: ModPath,
+        item_to_import: ItemInNs,
+        original_item: ItemInNs,
+    ) -> Self {
+        Self {
+            import_path,
+            item_to_import,
+            original_item,
+            complete_in_flyimport: CompleteInFlyimport(true),
+        }
     }
 }
 
@@ -351,12 +374,17 @@
                 // see also an ignored test under FIXME comment in the qualify_path.rs module
                 AssocSearchMode::Exclude,
             )
-            .filter_map(|item| {
+            .filter_map(|(item, do_not_complete)| {
                 if !scope_filter(item) {
                     return None;
                 }
                 let mod_path = mod_path(item)?;
-                Some(LocatedImport::new(mod_path, item, item))
+                Some(LocatedImport::new(
+                    mod_path,
+                    item,
+                    item,
+                    CompleteInFlyimport(do_not_complete != Complete::IgnoreFlyimport),
+                ))
             })
             .take(DEFAULT_QUERY_SEARCH_LIMIT)
             .collect()
@@ -371,7 +399,7 @@
             NameToImport::Exact(first_qsegment.as_str().to_owned(), true),
             AssocSearchMode::Exclude,
         )
-        .filter_map(|item| {
+        .filter_map(|(item, do_not_complete)| {
             // we found imports for `first_qsegment`, now we need to filter these imports by whether
             // they result in resolving the rest of the path successfully
             validate_resolvable(
@@ -382,6 +410,7 @@
                 &path_candidate.name,
                 item,
                 qualifier_rest,
+                CompleteInFlyimport(do_not_complete != Complete::IgnoreFlyimport),
             )
         })
         .take(DEFAULT_QUERY_SEARCH_LIMIT)
@@ -399,6 +428,7 @@
     candidate: &NameToImport,
     resolved_qualifier: ItemInNs,
     unresolved_qualifier: &[Name],
+    complete_in_flyimport: CompleteInFlyimport,
 ) -> Option<LocatedImport> {
     let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
 
@@ -434,7 +464,14 @@
                     false => ControlFlow::Continue(()),
                 },
             )
-            .map(|item| LocatedImport::new(import_path_candidate, resolved_qualifier, item));
+            .map(|item| {
+                LocatedImport::new(
+                    import_path_candidate,
+                    resolved_qualifier,
+                    item,
+                    complete_in_flyimport,
+                )
+            });
         }
         // FIXME
         ModuleDef::Trait(_) => return None,
@@ -472,6 +509,7 @@
             import_path_candidate.clone(),
             resolved_qualifier,
             assoc_to_item(assoc),
+            complete_in_flyimport,
         ))
     })
 }
@@ -510,15 +548,15 @@
     let env_traits = trait_candidate.receiver_ty.env_traits(db);
     let related_traits = inherent_traits.chain(env_traits).collect::<FxHashSet<_>>();
 
-    let mut required_assoc_items = FxHashSet::default();
+    let mut required_assoc_items = FxHashMap::default();
     let mut trait_candidates: FxHashSet<_> = items_locator::items_with_name(
         db,
         current_crate,
         trait_candidate.assoc_item_name.clone(),
         AssocSearchMode::AssocItemsOnly,
     )
-    .filter_map(|input| item_as_assoc(db, input))
-    .filter_map(|assoc| {
+    .filter_map(|(input, do_not_complete)| Some((item_as_assoc(db, input)?, do_not_complete)))
+    .filter_map(|(assoc, do_not_complete)| {
         if !trait_assoc_item && matches!(assoc, AssocItem::Const(_) | AssocItem::TypeAlias(_)) {
             return None;
         }
@@ -527,7 +565,8 @@
         if related_traits.contains(&assoc_item_trait) {
             return None;
         }
-        required_assoc_items.insert(assoc);
+        required_assoc_items
+            .insert(assoc, CompleteInFlyimport(do_not_complete != Complete::IgnoreFlyimport));
         Some(assoc_item_trait.into())
     })
     .collect();
@@ -599,7 +638,7 @@
             None,
             None,
             |assoc| {
-                if required_assoc_items.contains(&assoc) {
+                if let Some(&complete_in_flyimport) = required_assoc_items.get(&assoc) {
                     let located_trait = assoc.container_trait(db).filter(|&it| scope_filter(it))?;
                     let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
                     let import_path = trait_import_paths
@@ -610,6 +649,7 @@
                         import_path,
                         trait_item,
                         assoc_to_item(assoc),
+                        complete_in_flyimport,
                     ));
                 }
                 None::<()>
@@ -624,7 +664,7 @@
             None,
             |function| {
                 let assoc = function.as_assoc_item(db)?;
-                if required_assoc_items.contains(&assoc) {
+                if let Some(&complete_in_flyimport) = required_assoc_items.get(&assoc) {
                     let located_trait = assoc.container_trait(db).filter(|&it| scope_filter(it))?;
                     let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
                     let import_path = trait_import_paths
@@ -635,6 +675,7 @@
                         import_path,
                         trait_item,
                         assoc_to_item(assoc),
+                        complete_in_flyimport,
                     ));
                 }
                 None::<()>
diff --git a/crates/ide-db/src/items_locator.rs b/crates/ide-db/src/items_locator.rs
index 7a543d6..e938525 100644
--- a/crates/ide-db/src/items_locator.rs
+++ b/crates/ide-db/src/items_locator.rs
@@ -5,7 +5,7 @@
 use std::ops::ControlFlow;
 
 use either::Either;
-use hir::{Crate, ItemInNs, Module, import_map};
+use hir::{Complete, Crate, ItemInNs, Module, import_map};
 
 use crate::{
     RootDatabase,
@@ -25,7 +25,7 @@
     krate: Crate,
     name: NameToImport,
     assoc_item_search: AssocSearchMode,
-) -> impl Iterator<Item = ItemInNs> {
+) -> impl Iterator<Item = (ItemInNs, Complete)> {
     let _p = tracing::info_span!("items_with_name", name = name.text(), assoc_item_search = ?assoc_item_search, crate = ?krate.display_name(db).map(|name| name.to_string()))
         .entered();
 
@@ -123,26 +123,29 @@
     krate: Crate,
     local_query: symbol_index::Query,
     external_query: import_map::Query,
-) -> impl Iterator<Item = ItemInNs> {
+) -> impl Iterator<Item = (ItemInNs, Complete)> {
     let _p = tracing::info_span!("find_items").entered();
 
     // NOTE: `external_query` includes `assoc_item_search`, so we don't need to
     // filter on our own.
-    let external_importables =
-        krate.query_external_importables(db, external_query).map(|external_importable| {
-            match external_importable {
+    let external_importables = krate.query_external_importables(db, external_query).map(
+        |(external_importable, do_not_complete)| {
+            let external_importable = match external_importable {
                 Either::Left(module_def) => ItemInNs::from(module_def),
                 Either::Right(macro_def) => ItemInNs::from(macro_def),
-            }
-        });
+            };
+            (external_importable, do_not_complete)
+        },
+    );
 
     // Query the local crate using the symbol index.
     let mut local_results = Vec::new();
     local_query.search(&symbol_index::crate_symbols(db, krate), |local_candidate| {
-        local_results.push(match local_candidate.def {
+        let def = match local_candidate.def {
             hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
             def => ItemInNs::from(def),
-        });
+        };
+        local_results.push((def, local_candidate.do_not_complete));
         ControlFlow::<()>::Continue(())
     });
     local_results.into_iter().chain(external_importables)
diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt
index ea50745..8e342ec 100644
--- a/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -42,6 +42,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "Struct",
@@ -75,6 +76,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "mul1",
@@ -108,6 +110,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "mul2",
@@ -141,6 +144,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "s1",
@@ -174,6 +178,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "s1",
@@ -207,6 +212,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "s2",
@@ -240,6 +246,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
         ],
     ),
diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index d2d2426..6de25c0 100644
--- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -40,6 +40,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "CONST",
@@ -71,6 +72,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "CONST_WITH_INNER",
@@ -102,6 +104,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "Enum",
@@ -135,6 +138,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "ItemLikeMacro",
@@ -168,6 +172,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "Macro",
@@ -201,6 +206,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "STATIC",
@@ -232,6 +238,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "Struct",
@@ -265,6 +272,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "StructFromMacro",
@@ -295,6 +303,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "StructInFn",
@@ -330,6 +339,7 @@
                 ),
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "StructInNamedConst",
@@ -365,6 +375,7 @@
                 ),
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "StructInUnnamedConst",
@@ -398,6 +409,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "StructT",
@@ -431,6 +443,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "Trait",
@@ -462,6 +475,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "Trait",
@@ -495,6 +509,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "Union",
@@ -528,6 +543,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "a_mod",
@@ -563,6 +579,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "b_mod",
@@ -598,6 +615,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "define_struct",
@@ -631,6 +649,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "generic_impl_fn",
@@ -664,6 +683,7 @@
                 ),
                 is_alias: false,
                 is_assoc: true,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "impl_fn",
@@ -697,6 +717,7 @@
                 ),
                 is_alias: false,
                 is_assoc: true,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "macro_rules_macro",
@@ -730,6 +751,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "main",
@@ -761,6 +783,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "really_define_struct",
@@ -794,6 +817,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "trait_fn",
@@ -827,6 +851,7 @@
                 ),
                 is_alias: false,
                 is_assoc: true,
+                do_not_complete: Yes,
             },
         ],
     ),
@@ -873,6 +898,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
         ],
     ),
@@ -917,6 +943,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "IsThisJustATrait",
@@ -950,6 +977,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "StructInModB",
@@ -983,6 +1011,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "SuperItemLikeMacro",
@@ -1016,6 +1045,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
             FileSymbol {
                 name: "ThisStruct",
@@ -1049,6 +1079,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                do_not_complete: Yes,
             },
         ],
     ),
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index cc9b3ef..4841f48 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -521,4 +521,8 @@
     win64,
     array,
     boxed_slice,
+    completions,
+    ignore_flyimport,
+    ignore_flyimport_methods,
+    ignore_methods,
 }