rust/crates/ra_hir/src/nameres/raw.rs

336 lines
11 KiB
Rust
Raw Normal View History

2019-05-23 12:18:47 -05:00
use std::{sync::Arc, ops::Index};
2019-03-13 08:38:02 -05:00
use test_utils::tested_by;
2019-03-16 09:17:50 -05:00
use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
use ra_syntax::{
2019-03-16 09:17:50 -05:00
AstNode, SourceFile, AstPtr, TreeArc,
ast::{self, NameOwner, AttrsOwner},
};
2019-05-23 12:18:47 -05:00
use crate::{DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, AstIdMap, FileAstId, Either};
2019-03-26 05:53:50 -05:00
/// `RawItems` is a set of top-level items in a file (except for impls).
///
/// It is the input to name resolution algorithm. `RawItems` are not invalidated
/// on most edits.
2019-03-13 08:38:02 -05:00
#[derive(Debug, Default, PartialEq, Eq)]
pub struct RawItems {
modules: Arena<Module, ModuleData>,
imports: Arena<ImportId, ImportData>,
defs: Arena<Def, DefData>,
macros: Arena<Macro, MacroData>,
/// items for top-level module
items: Vec<RawItem>,
}
2019-03-16 09:17:50 -05:00
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportSourceMap {
2019-04-02 09:58:04 -05:00
map: ArenaMap<ImportId, ImportSourcePtr>,
}
2019-04-10 02:12:54 -05:00
type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
type ImportSource = Either<TreeArc<ast::UseTree>, TreeArc<ast::ExternCrateItem>>;
2019-04-02 09:58:04 -05:00
impl ImportSourcePtr {
fn to_node(self, file: &SourceFile) -> ImportSource {
2019-05-13 11:39:06 -05:00
self.map(
|ptr| ptr.to_node(file.syntax()).to_owned(),
|ptr| ptr.to_node(file.syntax()).to_owned(),
)
2019-04-02 09:58:04 -05:00
}
}
2019-03-16 09:17:50 -05:00
impl ImportSourceMap {
2019-04-02 09:58:04 -05:00
fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) {
self.map.insert(import, ptr)
2019-03-16 09:17:50 -05:00
}
2019-04-02 09:58:04 -05:00
pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource {
2019-03-16 09:17:50 -05:00
let file = match source {
ModuleSource::SourceFile(file) => &*file,
ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
};
2019-04-02 09:58:04 -05:00
self.map[import].to_node(file)
2019-03-16 09:17:50 -05:00
}
}
impl RawItems {
pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
2019-03-14 05:14:54 -05:00
db.raw_items_with_source_map(file_id).0
}
pub(crate) fn raw_items_with_source_map_query(
db: &impl DefDatabase,
file_id: HirFileId,
2019-03-14 05:14:54 -05:00
) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
let mut collector = RawItemsCollector {
raw_items: RawItems::default(),
2019-03-26 11:00:11 -05:00
source_ast_id_map: db.ast_id_map(file_id.into()),
2019-03-14 05:14:54 -05:00
source_map: ImportSourceMap::default(),
};
2019-05-13 17:42:59 -05:00
if let Some(node) = db.parse_or_expand(file_id) {
if let Some(source_file) = ast::SourceFile::cast(&node) {
collector.process_module(None, &*source_file);
}
}
2019-03-14 05:14:54 -05:00
(Arc::new(collector.raw_items), Arc::new(collector.source_map))
2019-03-13 08:38:02 -05:00
}
2019-03-26 05:53:50 -05:00
pub(super) fn items(&self) -> &[RawItem] {
2019-03-13 08:38:02 -05:00
&self.items
}
}
impl Index<Module> for RawItems {
type Output = ModuleData;
fn index(&self, idx: Module) -> &ModuleData {
&self.modules[idx]
}
}
impl Index<ImportId> for RawItems {
type Output = ImportData;
fn index(&self, idx: ImportId) -> &ImportData {
&self.imports[idx]
}
}
impl Index<Def> for RawItems {
type Output = DefData;
fn index(&self, idx: Def) -> &DefData {
&self.defs[idx]
}
}
impl Index<Macro> for RawItems {
type Output = MacroData;
fn index(&self, idx: Macro) -> &MacroData {
&self.macros[idx]
}
}
2019-03-13 08:38:02 -05:00
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
2019-03-26 05:53:50 -05:00
pub(super) enum RawItem {
Module(Module),
Import(ImportId),
Def(Def),
Macro(Macro),
}
2019-03-13 08:38:02 -05:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2019-03-26 05:53:50 -05:00
pub(super) struct Module(RawId);
impl_arena_id!(Module);
2019-03-13 08:38:02 -05:00
#[derive(Debug, PartialEq, Eq)]
2019-03-26 05:53:50 -05:00
pub(super) enum ModuleData {
2019-03-26 09:25:14 -05:00
Declaration { name: Name, ast_id: FileAstId<ast::Module> },
Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
}
2019-03-16 09:17:50 -05:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ImportId(RawId);
impl_arena_id!(ImportId);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImportData {
2019-03-26 05:53:50 -05:00
pub(super) path: Path,
pub(super) alias: Option<Name>,
pub(super) is_glob: bool,
pub(super) is_prelude: bool,
pub(super) is_extern_crate: bool,
2019-03-16 09:17:50 -05:00
}
2019-03-13 08:38:02 -05:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2019-03-26 05:53:50 -05:00
pub(super) struct Def(RawId);
impl_arena_id!(Def);
2019-03-13 08:38:02 -05:00
#[derive(Debug, PartialEq, Eq)]
2019-03-26 05:53:50 -05:00
pub(super) struct DefData {
pub(super) name: Name,
pub(super) kind: DefKind,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
2019-03-26 05:53:50 -05:00
pub(super) enum DefKind {
2019-03-26 10:27:22 -05:00
Function(FileAstId<ast::FnDef>),
Struct(FileAstId<ast::StructDef>),
2019-05-23 12:18:47 -05:00
Union(FileAstId<ast::StructDef>),
2019-03-26 10:27:22 -05:00
Enum(FileAstId<ast::EnumDef>),
Const(FileAstId<ast::ConstDef>),
Static(FileAstId<ast::StaticDef>),
Trait(FileAstId<ast::TraitDef>),
TypeAlias(FileAstId<ast::TypeAliasDef>),
}
2019-03-13 08:38:02 -05:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2019-03-26 05:53:50 -05:00
pub(super) struct Macro(RawId);
impl_arena_id!(Macro);
2019-03-13 08:38:02 -05:00
#[derive(Debug, PartialEq, Eq)]
2019-03-26 05:53:50 -05:00
pub(super) struct MacroData {
2019-03-26 10:03:17 -05:00
pub(super) ast_id: FileAstId<ast::MacroCall>,
2019-03-26 05:53:50 -05:00
pub(super) path: Path,
pub(super) name: Option<Name>,
pub(super) export: bool,
}
struct RawItemsCollector {
raw_items: RawItems,
2019-03-26 11:00:11 -05:00
source_ast_id_map: Arc<AstIdMap>,
2019-03-14 05:14:54 -05:00
source_map: ImportSourceMap,
}
impl RawItemsCollector {
fn process_module(&mut self, current_module: Option<Module>, body: &impl ast::ModuleItemOwner) {
for item_or_macro in body.items_with_macros() {
match item_or_macro {
ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
}
}
}
fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
let (kind, name) = match item.kind() {
ast::ModuleItemKind::Module(module) => {
self.add_module(current_module, module);
return;
}
ast::ModuleItemKind::UseItem(use_item) => {
self.add_use_item(current_module, use_item);
return;
}
ast::ModuleItemKind::ExternCrateItem(extern_crate) => {
self.add_extern_crate_item(current_module, extern_crate);
return;
}
ast::ModuleItemKind::ImplBlock(_) => {
// impls don't participate in name resolution
return;
}
2019-03-26 10:27:22 -05:00
ast::ModuleItemKind::StructDef(it) => {
2019-05-23 12:18:47 -05:00
let id = self.source_ast_id_map.ast_id(it);
let name = it.name();
if it.is_union() {
(DefKind::Union(id), name)
} else {
(DefKind::Struct(id), name)
}
2019-03-26 10:27:22 -05:00
}
ast::ModuleItemKind::EnumDef(it) => {
2019-03-26 11:00:11 -05:00
(DefKind::Enum(self.source_ast_id_map.ast_id(it)), it.name())
2019-03-26 10:27:22 -05:00
}
ast::ModuleItemKind::FnDef(it) => {
2019-03-26 11:00:11 -05:00
(DefKind::Function(self.source_ast_id_map.ast_id(it)), it.name())
2019-03-26 10:27:22 -05:00
}
ast::ModuleItemKind::TraitDef(it) => {
2019-03-26 11:00:11 -05:00
(DefKind::Trait(self.source_ast_id_map.ast_id(it)), it.name())
2019-03-26 10:27:22 -05:00
}
ast::ModuleItemKind::TypeAliasDef(it) => {
2019-03-26 11:00:11 -05:00
(DefKind::TypeAlias(self.source_ast_id_map.ast_id(it)), it.name())
2019-03-26 10:27:22 -05:00
}
ast::ModuleItemKind::ConstDef(it) => {
2019-03-26 11:00:11 -05:00
(DefKind::Const(self.source_ast_id_map.ast_id(it)), it.name())
2019-03-26 10:27:22 -05:00
}
ast::ModuleItemKind::StaticDef(it) => {
2019-03-26 11:00:11 -05:00
(DefKind::Static(self.source_ast_id_map.ast_id(it)), it.name())
2019-03-26 10:27:22 -05:00
}
};
if let Some(name) = name {
let name = name.as_name();
2019-03-26 10:27:22 -05:00
let def = self.raw_items.defs.alloc(DefData { name, kind });
self.push_item(current_module, RawItem::Def(def))
}
}
fn add_module(&mut self, current_module: Option<Module>, module: &ast::Module) {
let name = match module.name() {
Some(it) => it.as_name(),
None => return,
};
2019-03-26 11:00:11 -05:00
let ast_id = self.source_ast_id_map.ast_id(module);
if module.has_semi() {
2019-03-26 09:25:14 -05:00
let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
self.push_item(current_module, RawItem::Module(item));
return;
}
if let Some(item_list) = module.item_list() {
2019-03-13 08:38:02 -05:00
let item = self.raw_items.modules.alloc(ModuleData::Definition {
name,
2019-03-26 09:25:14 -05:00
ast_id,
2019-03-13 08:38:02 -05:00
items: Vec::new(),
});
self.process_module(Some(item), item_list);
self.push_item(current_module, RawItem::Module(item));
2019-03-13 08:38:02 -05:00
return;
}
2019-03-13 08:38:02 -05:00
tested_by!(name_res_works_for_broken_modules);
}
fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
let is_prelude = use_item.has_atom_attr("prelude_import");
Path::expand_use_item(use_item, |path, use_tree, is_glob, alias| {
2019-04-02 09:58:04 -05:00
let import_data =
ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false };
2019-04-10 02:12:54 -05:00
self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree)));
})
}
fn add_extern_crate_item(
&mut self,
current_module: Option<Module>,
extern_crate: &ast::ExternCrateItem,
) {
if let Some(name_ref) = extern_crate.name_ref() {
let path = Path::from_name_ref(name_ref);
let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
2019-04-02 09:58:04 -05:00
let import_data = ImportData {
path,
alias,
is_glob: false,
is_prelude: false,
is_extern_crate: true,
2019-04-02 09:58:04 -05:00
};
2019-04-10 02:12:54 -05:00
self.push_import(current_module, import_data, Either::B(AstPtr::new(extern_crate)));
}
}
fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
let path = match m.path().and_then(Path::from_ast) {
Some(it) => it,
_ => return,
};
let name = m.name().map(|it| it.as_name());
2019-03-26 11:00:11 -05:00
let ast_id = self.source_ast_id_map.ast_id(m);
let export = m.has_atom_attr("macro_export");
2019-03-26 10:03:17 -05:00
let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
self.push_item(current_module, RawItem::Macro(m));
}
2019-04-02 09:58:04 -05:00
fn push_import(
&mut self,
current_module: Option<Module>,
data: ImportData,
source: ImportSourcePtr,
) {
let import = self.raw_items.imports.alloc(data);
self.source_map.insert(import, source);
self.push_item(current_module, RawItem::Import(import))
}
fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
match current_module {
Some(module) => match &mut self.raw_items.modules[module] {
ModuleData::Definition { items, .. } => items,
ModuleData::Declaration { .. } => unreachable!(),
},
None => &mut self.raw_items.items,
}
.push(item)
}
}