Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/attr.rs')
| -rw-r--r-- | crates/hir-def/src/attr.rs | 148 |
1 files changed, 105 insertions, 43 deletions
diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index fd44493076..8a6b6f3eff 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -7,7 +7,7 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; use itertools::Itertools; -use la_arena::ArenaMap; +use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct}; use smallvec::{smallvec, SmallVec}; use syntax::{ @@ -19,12 +19,12 @@ use tt::Subtree; use crate::{ db::DefDatabase, intern::Interned, - item_tree::{ItemTreeId, ItemTreeNode}, - nameres::ModuleSource, + item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode}, + nameres::{ModuleOrigin, ModuleSource}, path::{ModPath, PathKind}, src::{HasChildSource, HasSource}, - AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, - MacroId, VariantId, + AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId, + VariantId, }; /// Holds documentation @@ -201,15 +201,23 @@ impl Attrs { db: &dyn DefDatabase, e: EnumId, ) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> { - let krate = e.lookup(db).container.krate; - let src = e.child_source(db); + // FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids let mut res = ArenaMap::default(); - for (id, var) in src.value.iter() { - let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn ast::HasAttrs)) - .filter(db, krate); - - res.insert(id, attrs) + let loc = e.lookup(db); + let krate = loc.container.krate; + let item_tree = loc.id.item_tree(db); + let enum_ = &item_tree[loc.id.value]; + let crate_graph = db.crate_graph(); + let cfg_options = &crate_graph[krate].cfg_options; + + let mut idx = 0; + for variant in enum_.variants.clone() { + let attrs = item_tree.attrs(db, krate, variant.into()); + if attrs.is_cfg_enabled(cfg_options) { + res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); + idx += 1; + } } Arc::new(res) @@ -219,18 +227,64 @@ impl Attrs { db: &dyn DefDatabase, v: VariantId, ) -> Arc<ArenaMap<LocalFieldId, Attrs>> { - let krate = v.module(db).krate; - let src = v.child_source(db); + // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); - for (id, fld) in src.value.iter() { - let owner: &dyn HasAttrs = match fld { - Either::Left(tuple) => tuple, - Either::Right(record) => record, - }; - let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate); + let crate_graph = db.crate_graph(); + let (fields, item_tree, krate) = match v { + VariantId::EnumVariantId(it) => { + let e = it.parent; + let loc = e.lookup(db); + let krate = loc.container.krate; + let item_tree = loc.id.item_tree(db); + let enum_ = &item_tree[loc.id.value]; + + let cfg_options = &crate_graph[krate].cfg_options; + let variant = 'tri: loop { + let mut idx = 0; + for variant in enum_.variants.clone() { + let attrs = item_tree.attrs(db, krate, variant.into()); + if attrs.is_cfg_enabled(cfg_options) { + if it.local_id == Idx::from_raw(RawIdx::from(idx)) { + break 'tri variant; + } + idx += 1; + } + } + return Arc::new(res); + }; + (item_tree[variant].fields.clone(), item_tree, krate) + } + VariantId::StructId(it) => { + let loc = it.lookup(db); + let krate = loc.container.krate; + let item_tree = loc.id.item_tree(db); + let struct_ = &item_tree[loc.id.value]; + (struct_.fields.clone(), item_tree, krate) + } + VariantId::UnionId(it) => { + let loc = it.lookup(db); + let krate = loc.container.krate; + let item_tree = loc.id.item_tree(db); + let union_ = &item_tree[loc.id.value]; + (union_.fields.clone(), item_tree, krate) + } + }; - res.insert(id, attrs); + let fields = match fields { + Fields::Record(fields) | Fields::Tuple(fields) => fields, + Fields::Unit => return Arc::new(res), + }; + + let cfg_options = &crate_graph[krate].cfg_options; + + let mut idx = 0; + for field in fields { + let attrs = item_tree.attrs(db, krate, field.into()); + if attrs.is_cfg_enabled(cfg_options) { + res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); + idx += 1; + } } Arc::new(res) @@ -243,11 +297,14 @@ impl Attrs { impl Attrs { pub fn cfg(&self) -> Option<CfgExpr> { - let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>(); - match cfgs.len() { - 0 => None, - 1 => Some(cfgs.pop().unwrap()), - _ => Some(CfgExpr::All(cfgs)), + let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse); + let first = cfgs.next()?; + match cfgs.next() { + Some(second) => { + let cfgs = [first, second].into_iter().chain(cfgs); + Some(CfgExpr::All(cfgs.collect())) + } + None => Some(first), } } pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { @@ -315,25 +372,30 @@ impl AttrsWithOwner { AttrDefId::ModuleId(module) => { let def_map = module.def_map(db); let mod_data = &def_map[module.local_id]; - match mod_data.declaration_source(db) { - Some(it) => { - let raw_attrs = RawAttrs::from_attrs_owner( - db, - it.as_ref().map(|it| it as &dyn ast::HasAttrs), - ); - match mod_data.definition_source(db) { - InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs - .merge(RawAttrs::from_attrs_owner(db, InFile::new(file_id, &file))), - _ => raw_attrs, - } + + match mod_data.origin { + ModuleOrigin::File { definition, declaration_tree_id, .. } => { + let decl_attrs = declaration_tree_id + .item_tree(db) + .raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into())) + .clone(); + let tree = db.file_item_tree(definition.into()); + let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone(); + decl_attrs.merge(def_attrs) + } + ModuleOrigin::CrateRoot { definition } => { + let tree = db.file_item_tree(definition.into()); + tree.raw_attrs(AttrOwner::TopLevel).clone() } - None => RawAttrs::from_attrs_owner( + ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id + .item_tree(db) + .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into())) + .clone(), + ModuleOrigin::BlockExpr { block } => RawAttrs::from_attrs_owner( db, - mod_data.definition_source(db).as_ref().map(|src| match src { - ModuleSource::SourceFile(file) => file as &dyn ast::HasAttrs, - ModuleSource::Module(module) => module as &dyn ast::HasAttrs, - ModuleSource::BlockExpr(block) => block as &dyn ast::HasAttrs, - }), + InFile::new(block.file_id, block.to_node(db.upcast())) + .as_ref() + .map(|it| it as &dyn ast::HasAttrs), ), } } |