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::{
}
/// 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, RawAttrs>,
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);
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(), data: Default::default() }
- }
-
fn shrink_to_fit(&mut self) {
if let Some(data) = &mut self.data {
let ItemTreeData {
}
}
+ 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 {
// This unwrap cannot fail, since it has either succeeded above, or resulted in an empty
// ItemTree (in which case there is no valid `FileItemTreeId` to call this method with).