mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-28 18:43:01 +00:00
Merge pull request #19375 from ChayimFriedman2/do-not-complete
feat: Allow crate authors to control completion of their things
This commit is contained in:
commit
2e1ff255ae
30 changed files with 770 additions and 293 deletions
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
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 struct FunctionData {
|
|||
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 @@ impl FunctionData {
|
|||
}
|
||||
|
||||
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 @@ impl FunctionData {
|
|||
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 struct TypeAliasData {
|
|||
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 @@ impl TypeAliasData {
|
|||
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 @@ impl TypeAliasData {
|
|||
|
||||
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 @@ impl Macro2Data {
|
|||
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 @@ impl MacroRulesData {
|
|||
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 @@ impl ProcMacroData {
|
|||
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 @@ impl ProcMacroData {
|
|||
stdx::never!("proc macro declaration is not a proc macro");
|
||||
(makro.name.clone(), None)
|
||||
};
|
||||
|
||||
Arc::new(ProcMacroData { name, helpers })
|
||||
}
|
||||
}
|
||||
|
|
@ -450,9 +491,16 @@ pub struct ConstData {
|
|||
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 @@ impl ConstData {
|
|||
} 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 struct StaticData {
|
|||
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 @@ impl StaticData {
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ impl StructData {
|
|||
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 @@ impl EnumData {
|
|||
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];
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ use itertools::Itertools;
|
|||
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 struct ImportInfo {
|
|||
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 @@ impl ImportMap {
|
|||
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 @@ impl ImportMap {
|
|||
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 @@ pub fn search_dependencies(
|
|||
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 @@ fn search_maps(
|
|||
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 @@ fn search_maps(
|
|||
})
|
||||
.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 @@ mod tests {
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ impl ItemScope {
|
|||
}
|
||||
|
||||
/// 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(),
|
||||
|
|
|
|||
|
|
@ -962,7 +962,7 @@ pub struct Param {
|
|||
|
||||
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 @@ bitflags::bitflags! {
|
|||
/// 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 Const {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ use crate::{
|
|||
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 @@ impl<'a> Ctx<'a> {
|
|||
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)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ use crate::{
|
|||
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 @@ impl Printer<'_> {
|
|||
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));
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub mod find_path;
|
|||
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 @@ use syntax::{AstNode, ast};
|
|||
pub use hir_expand::{Intern, Lookup, tt};
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
builtin_type::BuiltinType,
|
||||
data::adt::VariantData,
|
||||
db::DefDatabase,
|
||||
|
|
@ -1502,3 +1503,81 @@ pub struct UnresolvedMacro {
|
|||
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue