mod tests;
use std::{
- any::type_name,
fmt::{self, Debug},
hash::{Hash, Hasher},
marker::PhantomData,
- ops::{Index, Range},
+ ops::Index,
sync::Arc,
};
-use ast::{AstNode, NameOwner, StructKind};
+use ast::{AstNode, HasName, StructKind};
use base_db::CrateId;
use either::Either;
use hir_expand::{
ast_id_map::FileAstId,
hygiene::Hygiene,
name::{name, AsName, Name},
- FragmentKind, HirFileId, InFile,
+ ExpandTo, HirFileId, InFile,
};
-use la_arena::{Arena, Idx, RawIdx};
+use la_arena::{Arena, Idx, IdxRange, RawIdx};
use profile::Count;
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
+use stdx::never;
use syntax::{ast, match_ast, SyntaxKind};
use crate::{
impl ItemTree {
pub(crate) fn file_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 Default::default();
+ let _p = profile::span("file_item_tree_query").detail(|| format!("{:?}", file_id));
+ let syntax = match db.parse_or_expand(file_id) {
+ Some(node) => node,
+ None => return Default::default(),
};
+ if never!(syntax.kind() == SyntaxKind::ERROR) {
+ // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
+ return Default::default();
+ }
- let hygiene = Hygiene::new(db.upcast(), file_id);
- let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
+ let ctx = lower::Ctx::new(db, file_id);
let mut top_attrs = None;
let mut item_tree = match_ast! {
match syntax {
ast::SourceFile(file) => {
- top_attrs = Some(RawAttrs::new(db, &file, &hygiene));
+ top_attrs = Some(RawAttrs::new(db, &file, ctx.hygiene()));
ctx.lower_module_items(&file)
},
ast::MacroItems(items) => {
// items.
ctx.lower_macro_stmts(stmts)
},
- ast::Pat(_pat) => {
- // FIXME: This occurs because macros in pattern position are treated as inner
- // items and expanded during block DefMap computation
- return Default::default();
- },
- ast::Type(ty) => {
- // Types can contain inner items. We return an empty item tree in this case, but
- // still need to collect inner items.
- ctx.lower_inner_items(ty.syntax())
- },
- 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, syntax);
},
Arc::new(item_tree)
}
+ fn block_item_tree(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+ let loc = db.lookup_intern_block(block);
+ let block = loc.ast_id.to_node(db.upcast());
+ let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
+ Arc::new(ctx.lower_block(&block))
+ }
+
fn shrink_to_fit(&mut self) {
if let Some(data) = &mut self.data {
let ItemTreeData {
macro_rules,
macro_defs,
vis,
- inner_items,
} = &mut **data;
imports.shrink_to_fit();
macro_defs.shrink_to_fit();
vis.arena.shrink_to_fit();
-
- inner_items.shrink_to_fit();
}
}
self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
}
- pub fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
+ pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
self.raw_attrs(of).clone().filter(db, krate)
}
- 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 pretty_print(&self) -> String {
pretty::print_item_tree(self)
}
macro_defs: Arena<MacroDef>,
vis: ItemVisibilities,
-
- inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
}
#[derive(Debug, Eq, PartialEq, Hash)]
pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
match self.block {
- Some(_) => unreachable!("per-block ItemTrees are not yet implemented"),
+ Some(block) => ItemTree::block_item_tree(db, block),
None => db.file_item_tree(self.file),
}
}
pub(crate) fn file_id(self) -> HirFileId {
self.file
}
+
+ pub(crate) fn is_block(self) -> bool {
+ self.block.is_some()
+ }
}
#[derive(Debug)]
}
fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
- if let ModItem::$typ(id) = mod_item {
- Some(id)
- } else {
- None
+ match mod_item {
+ ModItem::$typ(id) => Some(id),
+ _ => None,
}
}
pub struct Function {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub explicit_generic_params: Interned<GenericParams>,
pub abi: Option<Interned<str>>,
- pub params: IdRange<Param>,
+ pub params: IdxRange<Param>,
pub ret_type: Interned<TypeRef>,
pub async_ret_type: Option<Interned<TypeRef>>,
pub ast_id: FileAstId<ast::Fn>,
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Param {
- Normal(Interned<TypeRef>),
+ Normal(Option<Name>, Interned<TypeRef>),
Varargs,
}
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
- pub variants: IdRange<Variant>,
+ pub variants: IdxRange<Variant>,
pub ast_id: FileAstId<ast::Enum>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Const {
- /// const _: () = ();
+ /// `None` for `const _: () = ();`
pub name: Option<Name>,
pub visibility: RawVisibilityId,
pub type_ref: Interned<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: Interned<TypeRef>,
pub ast_id: FileAstId<ast::Static>,
}
pub bounds: Box<[Interned<TypeBound>]>,
pub generic_params: Interned<GenericParams>,
pub type_ref: Option<Interned<TypeRef>>,
- pub is_extern: bool,
pub ast_id: FileAstId<ast::TypeAlias>,
}
/// Path to the called macro.
pub path: Interned<ModPath>,
pub ast_id: FileAstId<ast::MacroCall>,
- pub fragment: FragmentKind,
+ pub expand_to: ExpandTo,
}
#[derive(Debug, Clone, Eq, PartialEq)]
}
Some((prefix, ImportKind::Plain))
}
- (Some(prefix), PathKind::Super(0)) => {
- // `some::path::self` == `some::path`
- if path.segments().is_empty() {
- Some((prefix, ImportKind::TypeOnly))
- } else {
- None
+ (Some(mut prefix), PathKind::Super(n))
+ if *n > 0 && prefix.segments().is_empty() =>
+ {
+ // `super::super` + `super::rest`
+ match &mut prefix.kind {
+ PathKind::Super(m) => {
+ cov_mark::hit!(concat_super_mod_paths);
+ *m += *n;
+ for segment in path.segments() {
+ prefix.push_segment(segment.clone());
+ }
+ Some((prefix, ImportKind::Plain))
+ }
+ _ => None,
}
}
+ (Some(prefix), PathKind::Super(0)) if path.segments().is_empty() => {
+ // `some::path::self` == `some::path`
+ Some((prefix, ImportKind::TypeOnly))
+ }
(Some(_), _) => None,
}
}
}
}
+impl AssocItem {
+ pub fn ast_id(self, tree: &ItemTree) -> FileAstId<ast::AssocItem> {
+ match self {
+ AssocItem::Function(id) => tree[id].ast_id.upcast(),
+ AssocItem::TypeAlias(id) => tree[id].ast_id.upcast(),
+ AssocItem::Const(id) => tree[id].ast_id.upcast(),
+ AssocItem::MacroCall(id) => tree[id].ast_id.upcast(),
+ }
+ }
+}
+
#[derive(Debug, Eq, PartialEq)]
pub struct Variant {
pub name: Name,
pub fields: Fields,
}
-/// A range of densely allocated ItemTree IDs.
-pub struct IdRange<T> {
- range: Range<u32>,
- _p: PhantomData<T>,
-}
-
-impl<T> IdRange<T> {
- fn new(range: Range<Idx<T>>) -> Self {
- Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData }
- }
-
- fn is_empty(&self) -> bool {
- self.range.is_empty()
- }
-}
-
-impl<T> Iterator for IdRange<T> {
- type Item = Idx<T>;
- fn next(&mut self) -> Option<Self::Item> {
- self.range.next().map(|raw| Idx::from_raw(raw.into()))
- }
-}
-
-impl<T> DoubleEndedIterator for IdRange<T> {
- fn next_back(&mut self) -> Option<Self::Item> {
- self.range.next_back().map(|raw| Idx::from_raw(raw.into()))
- }
-}
-
-impl<T> fmt::Debug for IdRange<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()
- }
-}
-
-impl<T> Clone for IdRange<T> {
- fn clone(&self) -> Self {
- Self { range: self.range.clone(), _p: PhantomData }
- }
-}
-
-impl<T> PartialEq for IdRange<T> {
- fn eq(&self, other: &Self) -> bool {
- self.range == other.range
- }
-}
-
-impl<T> Eq for IdRange<T> {}
-
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Fields {
- Record(IdRange<Field>),
- Tuple(IdRange<Field>),
+ Record(IdxRange<Field>),
+ Tuple(IdxRange<Field>),
Unit,
}