sync::Arc,
};
-use arena::{Arena, Idx, RawId};
-use ast::{AstNode, AttrsOwner, NameOwner, StructKind};
+use ast::{AstNode, NameOwner, StructKind};
+use base_db::CrateId;
use either::Either;
use hir_expand::{
ast_id_map::FileAstId,
name::{name, AsName, Name},
HirFileId, InFile,
};
+use la_arena::{Arena, Idx, RawIdx};
+use profile::Count;
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
-use syntax::{ast, match_ast};
+use syntax::{ast, match_ast, SyntaxKind};
use test_utils::mark;
use crate::{
- attr::Attrs,
+ attr::{Attrs, RawAttrs},
db::DefDatabase,
generics::GenericParams,
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
}
/// The item tree of a source file.
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, Default, Eq, PartialEq)]
pub struct ItemTree {
+ _c: Count<Self>,
+
top_level: SmallVec<[ModItem; 1]>,
- attrs: FxHashMap<AttrOwner, Attrs>,
- inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
+ attrs: FxHashMap<AttrOwner, RawAttrs>,
data: Option<Box<ItemTreeData>>,
}
impl ItemTree {
- pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
+ pub(crate) fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id));
let syntax = if let Some(node) = db.parse_or_expand(file_id) {
+ if node.kind() == SyntaxKind::ERROR {
+ // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
+ return Default::default();
+ }
node
} else {
- return Arc::new(Self::empty());
+ return Default::default();
};
let hygiene = Hygiene::new(db.upcast(), file_id);
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())
+ // The produced statements can include items, which should be added as top-level
+ // items.
+ ctx.lower_macro_stmts(stmts)
},
- // Macros can expand to expressions. We return an empty item tree in this case, but
- // still need to collect inner items.
ast::Expr(e) => {
+ // Macros can expand to expressions. We return an empty item tree in this case, but
+ // still need to collect inner items.
ctx.lower_inner_items(e.syntax())
},
_ => {
- panic!("cannot create item tree from {:?}", syntax);
+ panic!("cannot create item tree from {:?} {}", syntax, syntax);
},
}
};
Arc::new(item_tree)
}
- fn empty() -> Self {
- Self {
- top_level: Default::default(),
- attrs: Default::default(),
- inner_items: Default::default(),
- data: Default::default(),
- }
- }
-
fn shrink_to_fit(&mut self) {
if let Some(data) = &mut self.data {
let ItemTreeData {
mods,
macro_calls,
macro_rules,
- exprs,
+ macro_defs,
vis,
generics,
+ inner_items,
} = &mut **data;
imports.shrink_to_fit();
mods.shrink_to_fit();
macro_calls.shrink_to_fit();
macro_rules.shrink_to_fit();
- exprs.shrink_to_fit();
+ macro_defs.shrink_to_fit();
vis.arena.shrink_to_fit();
generics.arena.shrink_to_fit();
+
+ inner_items.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 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)
}
- /// Returns the lowered inner items that `ast` corresponds to.
- ///
- /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
- /// to multiple items in the `ItemTree`.
- pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] {
- &self.inner_items[&ast]
+ pub fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
+ self.raw_attrs(of).clone().filter(db, krate)
}
pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
- self.inner_items.values().flatten().copied()
+ match &self.data {
+ Some(data) => Some(data.inner_items.values().flatten().copied()).into_iter().flatten(),
+ None => None.into_iter().flatten(),
+ }
+ }
+
+ pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] {
+ match &self.data {
+ Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]),
+ None => &[],
+ }
}
pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
if params.types.is_empty()
&& params.lifetimes.is_empty()
+ && params.consts.is_empty()
&& params.where_predicates.is_empty()
{
return GenericParamsId::EMPTY;
}
}
-static EMPTY_GENERICS: GenericParams =
- GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() };
+static EMPTY_GENERICS: GenericParams = GenericParams {
+ types: Arena::new(),
+ lifetimes: Arena::new(),
+ consts: Arena::new(),
+ where_predicates: Vec::new(),
+};
#[derive(Default, Debug, Eq, PartialEq)]
struct ItemTreeData {
mods: Arena<Mod>,
macro_calls: Arena<MacroCall>,
macro_rules: Arena<MacroRules>,
- exprs: Arena<Expr>,
+ macro_defs: Arena<MacroDef>,
vis: ItemVisibilities,
generics: GenericParamsStorage,
+
+ inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
}
#[derive(Debug, Eq, PartialEq, Hash)]
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 {
};
}
-impl_index!(fields: Field, variants: Variant, exprs: Expr);
+impl_index!(fields: Field, variants: Variant);
impl Index<RawVisibilityId> for ItemTree {
type Output = RawVisibility;
pub alias: Option<ImportAlias>,
pub visibility: RawVisibilityId,
pub is_glob: bool,
- pub is_prelude: bool,
/// 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>,
pub name: Name,
pub alias: Option<ImportAlias>,
pub visibility: RawVisibilityId,
- /// Whether this is a `#[macro_use] extern crate ...`.
- pub is_macro_use: bool,
pub ast_id: FileAstId<ast::ExternCrate>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroRules {
- /// For `macro_rules!` declarations, this is the name of the declared macro.
+ /// The name of the declared macro.
pub name: Name,
- /// 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::MacroRules>,
}
-// 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.
+/// "Macros 2.0" macro definition.
#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Expr;
+pub struct MacroDef {
+ pub name: Name,
+ pub visibility: RawVisibilityId,
+ pub ast_id: FileAstId<ast::MacroDef>,
+}
macro_rules! impl_froms {
($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
| ModItem::Trait(_)
| ModItem::Impl(_)
| ModItem::Mod(_)
- | ModItem::MacroRules(_) => None,
+ | 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)),
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(),
}
}
}