//! A simplified AST that only contains items.
mod lower;
-#[cfg(test)]
-mod tests;
use std::{
any::type_name,
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,
use test_utils::mark;
use crate::{
- attr::Attrs,
+ attr::{Attrs, RawAttrs},
db::DefDatabase,
generics::GenericParams,
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
#[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>>,
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) => {
ctx.lower_module_items(&items)
},
+ ast::MacroStmts(stmts) => {
+ ctx.lower_inner_items(stmts.syntax())
+ },
// Macros can expand to expressions. We return an empty item tree in this case, but
// still need to collect inner items.
ast::Expr(e) => {
type_aliases,
mods,
macro_calls,
+ macro_rules,
+ macro_defs,
exprs,
vis,
generics,
type_aliases.shrink_to_fit();
mods.shrink_to_fit();
macro_calls.shrink_to_fit();
+ macro_rules.shrink_to_fit();
+ macro_defs.shrink_to_fit();
exprs.shrink_to_fit();
vis.arena.shrink_to_fit();
}
/// 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(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
+ self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
}
- pub fn attrs(&self, of: AttrOwner) -> &Attrs {
- self.attrs.get(&of).unwrap_or(&Attrs::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.
impl GenericParamsStorage {
fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
- if params.types.is_empty() && params.where_predicates.is_empty() {
+ if params.types.is_empty()
+ && params.lifetimes.is_empty()
+ && params.where_predicates.is_empty()
+ {
return GenericParamsId::EMPTY;
}
}
static EMPTY_GENERICS: GenericParams =
- GenericParams { types: Arena::new(), where_predicates: Vec::new() };
+ GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() };
#[derive(Default, Debug, Eq, PartialEq)]
struct ItemTreeData {
type_aliases: Arena<TypeAlias>,
mods: Arena<Mod>,
macro_calls: Arena<MacroCall>,
+ macro_rules: Arena<MacroRules>,
+ macro_defs: Arena<MacroDef>,
exprs: Arena<Expr>,
vis: ItemVisibilities,
Variant(Idx<Variant>),
Field(Idx<Field>),
- // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
}
macro_rules! from_attrs {
TypeAlias in type_aliases -> ast::TypeAlias,
Mod in mods -> ast::Module,
MacroCall in macro_calls -> ast::MacroCall,
+ MacroRules in macro_rules -> ast::MacroRules,
+ MacroDef in macro_defs -> ast::MacroDef,
}
macro_rules! impl_index {
/// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
/// `Import`s can map to the same `use` item.
pub ast_id: FileAstId<ast::Use>,
+ /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`.
+ ///
+ /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting
+ /// precise diagnostics.
+ pub index: usize,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ExternCrate {
- pub path: ModPath,
+ pub name: Name,
pub alias: Option<ImportAlias>,
pub visibility: RawVisibilityId,
/// Whether this is a `#[macro_use] extern crate ...`.
pub visibility: RawVisibilityId,
pub generic_params: GenericParamsId,
pub has_self_param: bool,
+ pub has_body: bool,
pub is_unsafe: bool,
+ /// Whether the function is located in an `extern` block (*not* whether it is an
+ /// `extern "abi" fn`).
+ pub is_extern: bool,
pub params: Box<[TypeRef]>,
pub is_varargs: bool,
pub ret_type: TypeRef,
pub name: Name,
pub visibility: RawVisibilityId,
pub mutable: bool,
+ /// Whether the static is in an `extern` block.
+ pub is_extern: bool,
pub type_ref: TypeRef,
pub ast_id: FileAstId<ast::Static>,
}
pub bounds: Box<[TypeBound]>,
pub generic_params: GenericParamsId,
pub type_ref: Option<TypeRef>,
+ pub is_extern: bool,
pub ast_id: FileAstId<ast::TypeAlias>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroCall {
- /// For `macro_rules!` declarations, this is the name of the declared macro.
- pub name: Option<Name>,
/// Path to the called macro.
pub path: ModPath,
- /// Has `#[macro_export]`.
- pub is_export: bool,
- /// Has `#[macro_export(local_inner_macros)]`.
- pub is_local_inner: bool,
- /// Has `#[rustc_builtin_macro]`.
- pub is_builtin: bool,
pub ast_id: FileAstId<ast::MacroCall>,
}
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct MacroRules {
+ /// The name of the declared macro.
+ pub name: Name,
+ pub ast_id: FileAstId<ast::MacroRules>,
+}
+
+/// "Macros 2.0" macro definition.
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct MacroDef {
+ pub name: Name,
+ pub visibility: RawVisibilityId,
+ pub ast_id: FileAstId<ast::MacroDef>,
+}
+
// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
// lengths, but we don't do much with them yet.
#[derive(Debug, Clone, Eq, PartialEq)]
| ModItem::Static(_)
| ModItem::Trait(_)
| ModItem::Impl(_)
- | ModItem::Mod(_) => None,
+ | ModItem::Mod(_)
+ | ModItem::MacroRules(_)
+ | ModItem::MacroDef(_) => None,
ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
N::id_from_mod_item(self)
}
+
+ pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
+ match self {
+ ModItem::Import(it) => tree[it.index].ast_id().upcast(),
+ ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Function(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Struct(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Union(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Enum(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Const(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Static(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Trait(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Impl(it) => tree[it.index].ast_id().upcast(),
+ ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(),
+ ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
+ ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
+ ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
+ ModItem::MacroDef(it) => tree[it.index].ast_id().upcast(),
+ }
+ }
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]