mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Merge #6924
6924: Refactor attributes API to allow handling cfg_attr later r=jonas-schievink a=jonas-schievink bors r+ Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
commit
37e5f19373
8 changed files with 196 additions and 123 deletions
|
@ -3,6 +3,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use arena::{map::ArenaMap, Arena};
|
||||
use base_db::CrateId;
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
name::{AsName, Name},
|
||||
|
@ -66,8 +67,13 @@ pub enum ReprKind {
|
|||
Other,
|
||||
}
|
||||
|
||||
fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option<ReprKind> {
|
||||
item_tree.attrs(of).by_key("repr").tt_values().find_map(parse_repr_tt)
|
||||
fn repr_from_value(
|
||||
db: &dyn DefDatabase,
|
||||
krate: CrateId,
|
||||
item_tree: &ItemTree,
|
||||
of: AttrOwner,
|
||||
) -> Option<ReprKind> {
|
||||
item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
|
||||
}
|
||||
|
||||
fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
|
||||
|
@ -86,12 +92,13 @@ fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
|
|||
impl StructData {
|
||||
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.module(db).krate;
|
||||
let item_tree = db.item_tree(loc.id.file_id);
|
||||
let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into());
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
|
||||
|
||||
let strukt = &item_tree[loc.id.value];
|
||||
let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields, None);
|
||||
let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
|
||||
Arc::new(StructData {
|
||||
name: strukt.name.clone(),
|
||||
variant_data: Arc::new(variant_data),
|
||||
|
@ -100,12 +107,13 @@ impl StructData {
|
|||
}
|
||||
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.module(db).krate;
|
||||
let item_tree = db.item_tree(loc.id.file_id);
|
||||
let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into());
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
|
||||
|
||||
let union = &item_tree[loc.id.value];
|
||||
let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields, None);
|
||||
let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
|
||||
|
||||
Arc::new(StructData {
|
||||
name: union.name.clone(),
|
||||
|
@ -118,16 +126,23 @@ impl StructData {
|
|||
impl EnumData {
|
||||
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
|
||||
let loc = e.lookup(db);
|
||||
let krate = loc.container.module(db).krate;
|
||||
let item_tree = db.item_tree(loc.id.file_id);
|
||||
let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
|
||||
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
|
||||
|
||||
let enum_ = &item_tree[loc.id.value];
|
||||
let mut variants = Arena::new();
|
||||
for var_id in enum_.variants.clone() {
|
||||
if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) {
|
||||
if item_tree.attrs(db, krate, var_id.into()).is_cfg_enabled(&cfg_options) {
|
||||
let var = &item_tree[var_id];
|
||||
let var_data =
|
||||
lower_fields(&item_tree, &cfg_options, &var.fields, Some(enum_.visibility));
|
||||
let var_data = lower_fields(
|
||||
db,
|
||||
krate,
|
||||
&item_tree,
|
||||
&cfg_options,
|
||||
&var.fields,
|
||||
Some(enum_.visibility),
|
||||
);
|
||||
|
||||
variants.alloc(EnumVariantData {
|
||||
name: var.name.clone(),
|
||||
|
@ -170,7 +185,7 @@ fn lower_enum(
|
|||
.variant_list()
|
||||
.into_iter()
|
||||
.flat_map(|it| it.variants())
|
||||
.filter(|var| expander.is_cfg_enabled(var));
|
||||
.filter(|var| expander.is_cfg_enabled(db, var));
|
||||
for var in variants {
|
||||
trace.alloc(
|
||||
|| var.clone(),
|
||||
|
@ -262,7 +277,7 @@ fn lower_struct(
|
|||
match &ast.value {
|
||||
ast::StructKind::Tuple(fl) => {
|
||||
for (i, fd) in fl.fields().enumerate() {
|
||||
if !expander.is_cfg_enabled(&fd) {
|
||||
if !expander.is_cfg_enabled(db, &fd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -279,7 +294,7 @@ fn lower_struct(
|
|||
}
|
||||
ast::StructKind::Record(fl) => {
|
||||
for fd in fl.fields() {
|
||||
if !expander.is_cfg_enabled(&fd) {
|
||||
if !expander.is_cfg_enabled(db, &fd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -299,6 +314,8 @@ fn lower_struct(
|
|||
}
|
||||
|
||||
fn lower_fields(
|
||||
db: &dyn DefDatabase,
|
||||
krate: CrateId,
|
||||
item_tree: &ItemTree,
|
||||
cfg_options: &CfgOptions,
|
||||
fields: &Fields,
|
||||
|
@ -308,7 +325,7 @@ fn lower_fields(
|
|||
Fields::Record(flds) => {
|
||||
let mut arena = Arena::new();
|
||||
for field_id in flds.clone() {
|
||||
if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
|
||||
if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
|
||||
}
|
||||
}
|
||||
|
@ -317,7 +334,7 @@ fn lower_fields(
|
|||
Fields::Tuple(flds) => {
|
||||
let mut arena = Arena::new();
|
||||
for field_id in flds.clone() {
|
||||
if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
|
||||
if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use std::{ops, sync::Arc};
|
||||
|
||||
use base_db::CrateId;
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
use hir_expand::{hygiene::Hygiene, AstId, InFile};
|
||||
|
@ -38,12 +39,16 @@ impl From<Documentation> for String {
|
|||
}
|
||||
}
|
||||
|
||||
/// Syntactical attributes, without filtering of `cfg_attr`s.
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Attrs {
|
||||
pub struct RawAttrs {
|
||||
entries: Option<Arc<[Attr]>>,
|
||||
}
|
||||
|
||||
impl ops::Deref for Attrs {
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Attrs(RawAttrs);
|
||||
|
||||
impl ops::Deref for RawAttrs {
|
||||
type Target = [Attr];
|
||||
|
||||
fn deref(&self) -> &[Attr] {
|
||||
|
@ -54,62 +59,21 @@ impl ops::Deref for Attrs {
|
|||
}
|
||||
}
|
||||
|
||||
impl Attrs {
|
||||
pub const EMPTY: Attrs = Attrs { entries: None };
|
||||
impl ops::Deref for Attrs {
|
||||
type Target = [Attr];
|
||||
|
||||
pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
|
||||
match def {
|
||||
AttrDefId::ModuleId(module) => {
|
||||
let def_map = db.crate_def_map(module.krate);
|
||||
let mod_data = &def_map[module.local_id];
|
||||
match mod_data.declaration_source(db) {
|
||||
Some(it) => {
|
||||
Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner))
|
||||
}
|
||||
None => Attrs::from_attrs_owner(
|
||||
db,
|
||||
mod_data.definition_source(db).as_ref().map(|src| match src {
|
||||
ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
|
||||
ModuleSource::Module(module) => module as &dyn AttrsOwner,
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
AttrDefId::FieldId(it) => {
|
||||
let src = it.parent.child_source(db);
|
||||
match &src.value[it.local_id] {
|
||||
Either::Left(_tuple) => Attrs::default(),
|
||||
Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
|
||||
}
|
||||
}
|
||||
AttrDefId::EnumVariantId(var_id) => {
|
||||
let src = var_id.parent.child_source(db);
|
||||
let src = src.as_ref().map(|it| &it[var_id.local_id]);
|
||||
Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
|
||||
}
|
||||
AttrDefId::AdtId(it) => match it {
|
||||
AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
},
|
||||
AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::MacroDefId(it) => {
|
||||
it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
|
||||
}
|
||||
AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
fn deref(&self) -> &[Attr] {
|
||||
match &self.0.entries {
|
||||
Some(it) => &*it,
|
||||
None => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
|
||||
let hygiene = Hygiene::new(db.upcast(), owner.file_id);
|
||||
Attrs::new(owner.value, &hygiene)
|
||||
}
|
||||
impl RawAttrs {
|
||||
pub const EMPTY: Self = Self { entries: None };
|
||||
|
||||
pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
|
||||
pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self {
|
||||
let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
|
||||
.map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs))));
|
||||
|
||||
|
@ -137,17 +101,93 @@ impl Attrs {
|
|||
} else {
|
||||
Some(attrs.into_iter().flat_map(|(_, attr)| attr).collect())
|
||||
};
|
||||
Attrs { entries }
|
||||
Self { entries }
|
||||
}
|
||||
|
||||
fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Self {
|
||||
let hygiene = Hygiene::new(db.upcast(), owner.file_id);
|
||||
Self::new(owner.value, &hygiene)
|
||||
}
|
||||
|
||||
pub(crate) fn merge(&self, other: Self) -> Self {
|
||||
match (&self.entries, &other.entries) {
|
||||
(None, None) => Self::EMPTY,
|
||||
(Some(entries), None) | (None, Some(entries)) => {
|
||||
Self { entries: Some(entries.clone()) }
|
||||
}
|
||||
(Some(a), Some(b)) => {
|
||||
Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
|
||||
pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs {
|
||||
// FIXME actually implement this
|
||||
Attrs(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Attrs {
|
||||
pub const EMPTY: Self = Self(RawAttrs::EMPTY);
|
||||
|
||||
pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
|
||||
let raw_attrs = match def {
|
||||
AttrDefId::ModuleId(module) => {
|
||||
let def_map = db.crate_def_map(module.krate);
|
||||
let mod_data = &def_map[module.local_id];
|
||||
match mod_data.declaration_source(db) {
|
||||
Some(it) => {
|
||||
RawAttrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner))
|
||||
}
|
||||
None => RawAttrs::from_attrs_owner(
|
||||
db,
|
||||
mod_data.definition_source(db).as_ref().map(|src| match src {
|
||||
ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
|
||||
ModuleSource::Module(module) => module as &dyn AttrsOwner,
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
AttrDefId::FieldId(it) => {
|
||||
let src = it.parent.child_source(db);
|
||||
match &src.value[it.local_id] {
|
||||
Either::Left(_tuple) => RawAttrs::default(),
|
||||
Either::Right(record) => RawAttrs::from_attrs_owner(db, src.with_value(record)),
|
||||
}
|
||||
}
|
||||
AttrDefId::EnumVariantId(var_id) => {
|
||||
let src = var_id.parent.child_source(db);
|
||||
let src = src.as_ref().map(|it| &it[var_id.local_id]);
|
||||
RawAttrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
|
||||
}
|
||||
AttrDefId::AdtId(it) => match it {
|
||||
AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
},
|
||||
AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::MacroDefId(it) => {
|
||||
it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
|
||||
}
|
||||
AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
||||
};
|
||||
|
||||
raw_attrs.filter(db, def.krate(db))
|
||||
}
|
||||
|
||||
pub fn merge(&self, other: Attrs) -> Attrs {
|
||||
match (&self.entries, &other.entries) {
|
||||
(None, None) => Attrs { entries: None },
|
||||
match (&self.0.entries, &other.0.entries) {
|
||||
(None, None) => Attrs::EMPTY,
|
||||
(Some(entries), None) | (None, Some(entries)) => {
|
||||
Attrs { entries: Some(entries.clone()) }
|
||||
Attrs(RawAttrs { entries: Some(entries.clone()) })
|
||||
}
|
||||
(Some(a), Some(b)) => {
|
||||
Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
|
||||
Attrs(RawAttrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,16 +331,16 @@ impl<'a> AttrQuery<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs
|
||||
fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> RawAttrs
|
||||
where
|
||||
N: ast::AttrsOwner,
|
||||
{
|
||||
let src = InFile::new(src.file_id, src.to_node(db.upcast()));
|
||||
Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
|
||||
RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
|
||||
}
|
||||
|
||||
fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
|
||||
fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs {
|
||||
let tree = db.item_tree(id.file_id);
|
||||
let mod_item = N::id_to_mod_item(id.value);
|
||||
tree.attrs(mod_item.into()).clone()
|
||||
tree.raw_attrs(mod_item.into()).clone()
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ use test_utils::mark;
|
|||
pub(crate) use lower::LowerCtx;
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
attr::{Attrs, RawAttrs},
|
||||
db::DefDatabase,
|
||||
expr::{Expr, ExprId, Pat, PatId},
|
||||
item_scope::BuiltinShadowMode,
|
||||
|
@ -40,6 +40,7 @@ use crate::{
|
|||
pub(crate) struct CfgExpander {
|
||||
cfg_options: CfgOptions,
|
||||
hygiene: Hygiene,
|
||||
krate: CrateId,
|
||||
}
|
||||
|
||||
pub(crate) struct Expander {
|
||||
|
@ -65,15 +66,15 @@ impl CfgExpander {
|
|||
) -> CfgExpander {
|
||||
let hygiene = Hygiene::new(db.upcast(), current_file_id);
|
||||
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
|
||||
CfgExpander { cfg_options, hygiene }
|
||||
CfgExpander { cfg_options, hygiene, krate }
|
||||
}
|
||||
|
||||
pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
|
||||
Attrs::new(owner, &self.hygiene)
|
||||
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
|
||||
RawAttrs::new(owner, &self.hygiene).filter(db, self.krate)
|
||||
}
|
||||
|
||||
pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
|
||||
let attrs = self.parse_attrs(owner);
|
||||
pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool {
|
||||
let attrs = self.parse_attrs(db, owner);
|
||||
attrs.is_cfg_enabled(&self.cfg_options)
|
||||
}
|
||||
}
|
||||
|
@ -189,8 +190,8 @@ impl Expander {
|
|||
InFile { file_id: self.current_file_id, value }
|
||||
}
|
||||
|
||||
pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
|
||||
self.cfg_expander.parse_attrs(owner)
|
||||
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
|
||||
self.cfg_expander.parse_attrs(db, owner)
|
||||
}
|
||||
|
||||
pub(crate) fn cfg_options(&self) -> &CfgOptions {
|
||||
|
|
|
@ -963,7 +963,7 @@ impl ExprCollector<'_> {
|
|||
/// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
|
||||
/// not.
|
||||
fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> {
|
||||
match self.expander.parse_attrs(owner).cfg() {
|
||||
match self.expander.parse_attrs(self.db, owner).cfg() {
|
||||
Some(cfg) => {
|
||||
if self.expander.cfg_options().check(&cfg) != Some(false) {
|
||||
return Some(());
|
||||
|
|
|
@ -35,6 +35,7 @@ pub struct FunctionData {
|
|||
impl FunctionData {
|
||||
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
|
||||
let loc = func.lookup(db);
|
||||
let krate = loc.container.module(db).krate;
|
||||
let item_tree = db.item_tree(loc.id.file_id);
|
||||
let func = &item_tree[loc.id.value];
|
||||
|
||||
|
@ -42,7 +43,7 @@ impl FunctionData {
|
|||
name: func.name.clone(),
|
||||
params: func.params.to_vec(),
|
||||
ret_type: func.ret_type.clone(),
|
||||
attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
|
||||
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()).clone(),
|
||||
has_self_param: func.has_self_param,
|
||||
has_body: func.has_body,
|
||||
is_unsafe: func.is_unsafe,
|
||||
|
@ -233,7 +234,7 @@ fn collect_items(
|
|||
match item {
|
||||
AssocItem::Function(id) => {
|
||||
let item = &item_tree[id];
|
||||
let attrs = item_tree.attrs(ModItem::from(id).into());
|
||||
let attrs = item_tree.attrs(db, module.krate, ModItem::from(id).into());
|
||||
if !attrs.is_cfg_enabled(&cfg_options) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use std::{
|
|||
|
||||
use arena::{Arena, Idx, RawId};
|
||||
use ast::{AstNode, AttrsOwner, NameOwner, StructKind};
|
||||
use base_db::CrateId;
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
ast_id_map::FileAstId,
|
||||
|
@ -26,7 +27,7 @@ use syntax::{ast, match_ast};
|
|||
use test_utils::mark;
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
attr::{Attrs, RawAttrs},
|
||||
db::DefDatabase,
|
||||
generics::GenericParams,
|
||||
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
||||
|
@ -67,7 +68,7 @@ impl GenericParamsId {
|
|||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct ItemTree {
|
||||
top_level: SmallVec<[ModItem; 1]>,
|
||||
attrs: FxHashMap<AttrOwner, Attrs>,
|
||||
attrs: FxHashMap<AttrOwner, RawAttrs>,
|
||||
inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
|
||||
|
||||
data: Option<Box<ItemTreeData>>,
|
||||
|
@ -88,7 +89,7 @@ impl ItemTree {
|
|||
let mut item_tree = match_ast! {
|
||||
match syntax {
|
||||
ast::SourceFile(file) => {
|
||||
top_attrs = Some(Attrs::new(&file, &hygiene));
|
||||
top_attrs = Some(RawAttrs::new(&file, &hygiene));
|
||||
ctx.lower_module_items(&file)
|
||||
},
|
||||
ast::MacroItems(items) => {
|
||||
|
@ -180,12 +181,16 @@ impl ItemTree {
|
|||
}
|
||||
|
||||
/// Returns the inner attributes of the source file.
|
||||
pub fn top_level_attrs(&self) -> &Attrs {
|
||||
self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY)
|
||||
pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
|
||||
self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone().filter(db, krate)
|
||||
}
|
||||
|
||||
pub fn attrs(&self, of: AttrOwner) -> &Attrs {
|
||||
self.attrs.get(&of).unwrap_or(&Attrs::EMPTY)
|
||||
pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
|
||||
self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
|
||||
}
|
||||
|
||||
pub fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
|
||||
self.raw_attrs(of).clone().filter(db, krate)
|
||||
}
|
||||
|
||||
/// Returns the lowered inner items that `ast` corresponds to.
|
||||
|
|
|
@ -10,7 +10,6 @@ use syntax::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
generics::{GenericParams, TypeParamData, TypeParamProvenance},
|
||||
type_ref::LifetimeRef,
|
||||
};
|
||||
|
@ -105,7 +104,7 @@ impl Ctx {
|
|||
| ast::Item::MacroDef(_) => {}
|
||||
};
|
||||
|
||||
let attrs = Attrs::new(item, &self.hygiene);
|
||||
let attrs = RawAttrs::new(item, &self.hygiene);
|
||||
let items = match item {
|
||||
ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
|
||||
ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
|
||||
|
@ -138,7 +137,7 @@ impl Ctx {
|
|||
items
|
||||
}
|
||||
|
||||
fn add_attrs(&mut self, item: AttrOwner, attrs: Attrs) {
|
||||
fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
|
||||
match self.tree.attrs.entry(item) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() = entry.get().merge(attrs);
|
||||
|
@ -205,7 +204,7 @@ impl Ctx {
|
|||
for field in fields.fields() {
|
||||
if let Some(data) = self.lower_record_field(&field) {
|
||||
let idx = self.data().fields.alloc(data);
|
||||
self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
|
||||
self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene));
|
||||
}
|
||||
}
|
||||
let end = self.next_field_idx();
|
||||
|
@ -225,7 +224,7 @@ impl Ctx {
|
|||
for (i, field) in fields.fields().enumerate() {
|
||||
let data = self.lower_tuple_field(i, &field);
|
||||
let idx = self.data().fields.alloc(data);
|
||||
self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
|
||||
self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene));
|
||||
}
|
||||
let end = self.next_field_idx();
|
||||
IdRange::new(start..end)
|
||||
|
@ -270,7 +269,7 @@ impl Ctx {
|
|||
for variant in variants.variants() {
|
||||
if let Some(data) = self.lower_variant(&variant) {
|
||||
let idx = self.data().variants.alloc(data);
|
||||
self.add_attrs(idx.into(), Attrs::new(&variant, &self.hygiene));
|
||||
self.add_attrs(idx.into(), RawAttrs::new(&variant, &self.hygiene));
|
||||
}
|
||||
}
|
||||
let end = self.next_variant_idx();
|
||||
|
@ -438,7 +437,7 @@ impl Ctx {
|
|||
self.with_inherited_visibility(visibility, |this| {
|
||||
list.assoc_items()
|
||||
.filter_map(|item| {
|
||||
let attrs = Attrs::new(&item, &this.hygiene);
|
||||
let attrs = RawAttrs::new(&item, &this.hygiene);
|
||||
this.collect_inner_items(item.syntax());
|
||||
this.lower_assoc_item(&item).map(|item| {
|
||||
this.add_attrs(ModItem::from(item).into(), attrs);
|
||||
|
@ -475,7 +474,7 @@ impl Ctx {
|
|||
.filter_map(|item| {
|
||||
self.collect_inner_items(item.syntax());
|
||||
let assoc = self.lower_assoc_item(&item)?;
|
||||
let attrs = Attrs::new(&item, &self.hygiene);
|
||||
let attrs = RawAttrs::new(&item, &self.hygiene);
|
||||
self.add_attrs(ModItem::from(assoc).into(), attrs);
|
||||
Some(assoc)
|
||||
})
|
||||
|
@ -560,7 +559,7 @@ impl Ctx {
|
|||
list.extern_items()
|
||||
.filter_map(|item| {
|
||||
self.collect_inner_items(item.syntax());
|
||||
let attrs = Attrs::new(&item, &self.hygiene);
|
||||
let attrs = RawAttrs::new(&item, &self.hygiene);
|
||||
let id: ModItem = match item {
|
||||
ast::ExternItem::Fn(ast) => {
|
||||
let func_id = self.lower_function(&ast)?;
|
||||
|
|
|
@ -221,17 +221,20 @@ impl DefCollector<'_> {
|
|||
let item_tree = self.db.item_tree(file_id.into());
|
||||
let module_id = self.def_map.root;
|
||||
self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
|
||||
let mut root_collector = ModCollector {
|
||||
def_collector: &mut *self,
|
||||
macro_depth: 0,
|
||||
module_id,
|
||||
file_id: file_id.into(),
|
||||
item_tree: &item_tree,
|
||||
mod_dir: ModDir::root(),
|
||||
};
|
||||
if item_tree.top_level_attrs().cfg().map_or(true, |cfg| root_collector.is_cfg_enabled(&cfg))
|
||||
if item_tree
|
||||
.top_level_attrs(self.db, self.def_map.krate)
|
||||
.cfg()
|
||||
.map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false))
|
||||
{
|
||||
root_collector.collect(item_tree.top_level_items());
|
||||
ModCollector {
|
||||
def_collector: &mut *self,
|
||||
macro_depth: 0,
|
||||
module_id,
|
||||
file_id: file_id.into(),
|
||||
item_tree: &item_tree,
|
||||
mod_dir: ModDir::root(),
|
||||
}
|
||||
.collect(item_tree.top_level_items());
|
||||
}
|
||||
|
||||
// main name resolution fixed-point loop.
|
||||
|
@ -905,6 +908,8 @@ struct ModCollector<'a, 'b> {
|
|||
|
||||
impl ModCollector<'_, '_> {
|
||||
fn collect(&mut self, items: &[ModItem]) {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
|
||||
// Note: don't assert that inserted value is fresh: it's simply not true
|
||||
// for macros.
|
||||
self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
|
||||
|
@ -921,7 +926,7 @@ impl ModCollector<'_, '_> {
|
|||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||
// any other items.
|
||||
for item in items {
|
||||
let attrs = self.item_tree.attrs((*item).into());
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, (*item).into());
|
||||
if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
|
||||
if let ModItem::ExternCrate(id) = item {
|
||||
let import = self.item_tree[*id].clone();
|
||||
|
@ -933,7 +938,7 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
|
||||
for &item in items {
|
||||
let attrs = self.item_tree.attrs(item.into());
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
||||
if let Some(cfg) = attrs.cfg() {
|
||||
if !self.is_cfg_enabled(&cfg) {
|
||||
self.emit_unconfigured_diagnostic(item, &cfg);
|
||||
|
@ -946,7 +951,7 @@ impl ModCollector<'_, '_> {
|
|||
|
||||
let mut def = None;
|
||||
match item {
|
||||
ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs),
|
||||
ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs),
|
||||
ModItem::Import(import_id) => {
|
||||
self.def_collector.unresolved_imports.push(ImportDirective {
|
||||
module_id: self.module_id,
|
||||
|
@ -975,7 +980,11 @@ impl ModCollector<'_, '_> {
|
|||
|
||||
// "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it
|
||||
// to define builtin macros, so we support at least that part.
|
||||
let attrs = self.item_tree.attrs(ModItem::from(id).into());
|
||||
let attrs = self.item_tree.attrs(
|
||||
self.def_collector.db,
|
||||
krate,
|
||||
ModItem::from(id).into(),
|
||||
);
|
||||
if attrs.by_key("rustc_builtin_macro").exists() {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
|
||||
|
@ -1012,7 +1021,7 @@ impl ModCollector<'_, '_> {
|
|||
ModItem::Function(id) => {
|
||||
let func = &self.item_tree[id];
|
||||
|
||||
self.collect_proc_macro_def(&func.name, attrs);
|
||||
self.collect_proc_macro_def(&func.name, &attrs);
|
||||
|
||||
def = Some(DefData {
|
||||
id: FunctionLoc {
|
||||
|
@ -1032,7 +1041,7 @@ impl ModCollector<'_, '_> {
|
|||
// FIXME: check attrs to see if this is an attribute macro invocation;
|
||||
// in which case we don't add the invocation, just a single attribute
|
||||
// macro invocation
|
||||
self.collect_derives(attrs, it.ast_id.upcast());
|
||||
self.collect_derives(&attrs, it.ast_id.upcast());
|
||||
|
||||
def = Some(DefData {
|
||||
id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) }
|
||||
|
@ -1049,7 +1058,7 @@ impl ModCollector<'_, '_> {
|
|||
// FIXME: check attrs to see if this is an attribute macro invocation;
|
||||
// in which case we don't add the invocation, just a single attribute
|
||||
// macro invocation
|
||||
self.collect_derives(attrs, it.ast_id.upcast());
|
||||
self.collect_derives(&attrs, it.ast_id.upcast());
|
||||
|
||||
def = Some(DefData {
|
||||
id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) }
|
||||
|
@ -1066,7 +1075,7 @@ impl ModCollector<'_, '_> {
|
|||
// FIXME: check attrs to see if this is an attribute macro invocation;
|
||||
// in which case we don't add the invocation, just a single attribute
|
||||
// macro invocation
|
||||
self.collect_derives(attrs, it.ast_id.upcast());
|
||||
self.collect_derives(&attrs, it.ast_id.upcast());
|
||||
|
||||
def = Some(DefData {
|
||||
id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) }
|
||||
|
@ -1303,8 +1312,9 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
|
||||
fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
let mac = &self.item_tree[id];
|
||||
let attrs = self.item_tree.attrs(ModItem::from(id).into());
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
|
||||
let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
|
||||
|
||||
let export_attr = attrs.by_key("macro_export");
|
||||
|
|
Loading…
Reference in a new issue