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

430 lines
13 KiB
Rust
Raw Normal View History

//! FIXME: write short doc here
use std::{ops::Index, sync::Arc};
use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
use ra_syntax::{
ast::{self, AttrsOwner, NameOwner},
2019-07-19 07:43:01 +00:00
AstNode, AstPtr, SmolStr, SourceFile,
};
use test_utils::tested_by;
use crate::{
attr::Attr,
2019-09-08 06:53:49 +00:00
db::{AstDatabase, DefDatabase},
AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source,
};
2019-03-26 10:53:50 +00: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 13:38:02 +00: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 14:17:50 +00:00
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportSourceMap {
2019-04-02 14:58:04 +00:00
map: ArenaMap<ImportId, ImportSourcePtr>,
}
2019-04-10 07:12:54 +00:00
type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
2019-07-19 07:43:01 +00:00
type ImportSource = Either<ast::UseTree, ast::ExternCrateItem>;
2019-04-02 14:58:04 +00:00
impl ImportSourcePtr {
fn to_node(self, file: &SourceFile) -> ImportSource {
2019-09-25 01:32:01 +00:00
self.map(|ptr| ptr.to_node(file.syntax()), |ptr| ptr.to_node(file.syntax()))
2019-04-02 14:58:04 +00:00
}
}
2019-03-16 14:17:50 +00:00
impl ImportSourceMap {
2019-04-02 14:58:04 +00:00
fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) {
self.map.insert(import, ptr)
2019-03-16 14:17:50 +00:00
}
2019-04-02 14:58:04 +00:00
pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource {
2019-03-16 14:17:50 +00:00
let file = match source {
2019-07-19 07:43:01 +00:00
ModuleSource::SourceFile(file) => file.clone(),
2019-03-16 14:17:50 +00:00
ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
};
2019-07-19 07:43:01 +00:00
self.map[import].to_node(&file)
2019-03-16 14:17:50 +00:00
}
}
impl RawItems {
2019-06-01 18:17:57 +00:00
pub(crate) fn raw_items_query(
db: &(impl DefDatabase + AstDatabase),
file_id: HirFileId,
) -> Arc<RawItems> {
2019-03-14 10:14:54 +00:00
db.raw_items_with_source_map(file_id).0
}
pub(crate) fn raw_items_with_source_map_query(
2019-06-01 18:17:57 +00:00
db: &(impl DefDatabase + AstDatabase),
file_id: HirFileId,
2019-03-14 10:14:54 +00:00
) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
let mut collector = RawItemsCollector {
raw_items: RawItems::default(),
2019-06-03 14:21:08 +00:00
source_ast_id_map: db.ast_id_map(file_id),
2019-03-14 10:14:54 +00:00
source_map: ImportSourceMap::default(),
file_id,
db,
};
2019-05-13 22:42:59 +00:00
if let Some(node) = db.parse_or_expand(file_id) {
2019-09-10 19:12:37 +00:00
if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
2019-07-19 07:43:01 +00:00
collector.process_module(None, source_file);
2019-09-10 19:12:37 +00:00
} else if let Some(item_list) = ast::MacroItems::cast(node) {
collector.process_module(None, item_list);
2019-05-13 22:42:59 +00:00
}
}
2019-03-14 10:14:54 +00:00
(Arc::new(collector.raw_items), Arc::new(collector.source_map))
2019-03-13 13:38:02 +00:00
}
2019-03-26 10:53:50 +00:00
pub(super) fn items(&self) -> &[RawItem] {
2019-03-13 13:38:02 +00: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]
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub(super) struct RawItem {
pub(super) attrs: Arc<[Attr]>,
pub(super) kind: RawItemKind,
}
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(super) enum RawItemKind {
Module(Module),
Import(ImportId),
Def(Def),
Macro(Macro),
}
2019-03-13 13:38:02 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2019-03-26 10:53:50 +00:00
pub(super) struct Module(RawId);
impl_arena_id!(Module);
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq)]
2019-03-26 10:53:50 +00:00
pub(super) enum ModuleData {
Declaration {
name: Name,
ast_id: FileAstId<ast::Module>,
attr_path: Option<SmolStr>,
2019-09-06 16:55:58 +00:00
is_macro_use: bool,
},
Definition {
name: Name,
ast_id: FileAstId<ast::Module>,
items: Vec<RawItem>,
attr_path: Option<SmolStr>,
2019-09-06 16:55:58 +00:00
is_macro_use: bool,
},
}
2019-03-16 14:17:50 +00: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 10:53:50 +00: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,
pub(super) is_macro_use: bool,
2019-03-16 14:17:50 +00:00
}
2019-03-13 13:38:02 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2019-03-26 10:53:50 +00:00
pub(super) struct Def(RawId);
impl_arena_id!(Def);
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq)]
2019-03-26 10:53:50 +00:00
pub(super) struct DefData {
pub(super) name: Name,
pub(super) kind: DefKind,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
2019-03-26 10:53:50 +00:00
pub(super) enum DefKind {
2019-03-26 15:27:22 +00:00
Function(FileAstId<ast::FnDef>),
Struct(FileAstId<ast::StructDef>),
2019-05-23 17:18:47 +00:00
Union(FileAstId<ast::StructDef>),
2019-03-26 15:27:22 +00:00
Enum(FileAstId<ast::EnumDef>),
Const(FileAstId<ast::ConstDef>),
Static(FileAstId<ast::StaticDef>),
Trait(FileAstId<ast::TraitDef>),
TypeAlias(FileAstId<ast::TypeAliasDef>),
}
2019-03-13 13:38:02 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2019-03-26 10:53:50 +00:00
pub(super) struct Macro(RawId);
impl_arena_id!(Macro);
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq)]
2019-03-26 10:53:50 +00:00
pub(super) struct MacroData {
2019-03-26 15:03:17 +00:00
pub(super) ast_id: FileAstId<ast::MacroCall>,
2019-03-26 10:53:50 +00:00
pub(super) path: Path,
pub(super) name: Option<Name>,
pub(super) export: bool,
}
struct RawItemsCollector<DB> {
raw_items: RawItems,
2019-03-26 16:00:11 +00:00
source_ast_id_map: Arc<AstIdMap>,
2019-03-14 10:14:54 +00:00
source_map: ImportSourceMap,
file_id: HirFileId,
db: DB,
}
2019-09-27 02:55:25 +00:00
impl<DB: AstDatabase> RawItemsCollector<&DB> {
2019-07-19 07:43:01 +00:00
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),
}
}
}
2019-07-19 07:43:01 +00:00
fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) {
let attrs = self.parse_attrs(&item);
2019-08-19 11:04:51 +00:00
let (kind, name) = match item {
ast::ModuleItem::Module(module) => {
self.add_module(current_module, module);
return;
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::UseItem(use_item) => {
self.add_use_item(current_module, use_item);
return;
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::ExternCrateItem(extern_crate) => {
self.add_extern_crate_item(current_module, extern_crate);
return;
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::ImplBlock(_) => {
// impls don't participate in name resolution
return;
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::StructDef(it) => {
2019-07-19 07:43:01 +00:00
let id = self.source_ast_id_map.ast_id(&it);
2019-05-23 17:18:47 +00:00
let name = it.name();
if it.is_union() {
(DefKind::Union(id), name)
} else {
(DefKind::Struct(id), name)
}
2019-03-26 15:27:22 +00:00
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::EnumDef(it) => {
2019-07-19 07:43:01 +00:00
(DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name())
2019-03-26 15:27:22 +00:00
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::FnDef(it) => {
2019-07-19 07:43:01 +00:00
(DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
2019-03-26 15:27:22 +00:00
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::TraitDef(it) => {
2019-07-19 07:43:01 +00:00
(DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name())
2019-03-26 15:27:22 +00:00
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::TypeAliasDef(it) => {
2019-07-19 07:43:01 +00:00
(DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name())
2019-03-26 15:27:22 +00:00
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::ConstDef(it) => {
2019-07-19 07:43:01 +00:00
(DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name())
2019-03-26 15:27:22 +00:00
}
2019-08-19 11:04:51 +00:00
ast::ModuleItem::StaticDef(it) => {
2019-07-19 07:43:01 +00:00
(DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
2019-03-26 15:27:22 +00:00
}
};
if let Some(name) = name {
let name = name.as_name();
2019-03-26 15:27:22 +00:00
let def = self.raw_items.defs.alloc(DefData { name, kind });
self.push_item(current_module, attrs, RawItemKind::Def(def));
}
}
2019-07-19 07:43:01 +00:00
fn add_module(&mut self, current_module: Option<Module>, module: ast::Module) {
let name = match module.name() {
Some(it) => it.as_name(),
None => return,
};
let attrs = self.parse_attrs(&module);
2019-07-19 07:43:01 +00:00
let ast_id = self.source_ast_id_map.ast_id(&module);
// FIXME: cfg_attr
2019-09-06 16:55:58 +00:00
let is_macro_use = module.has_atom_attr("macro_use");
if module.has_semi() {
let attr_path = extract_mod_path_attribute(&module);
2019-09-06 16:55:58 +00:00
let item = self.raw_items.modules.alloc(ModuleData::Declaration {
name,
ast_id,
attr_path,
is_macro_use,
});
self.push_item(current_module, attrs, RawItemKind::Module(item));
return;
}
if let Some(item_list) = module.item_list() {
let attr_path = extract_mod_path_attribute(&module);
2019-03-13 13:38:02 +00:00
let item = self.raw_items.modules.alloc(ModuleData::Definition {
name,
2019-03-26 14:25:14 +00:00
ast_id,
2019-03-13 13:38:02 +00:00
items: Vec::new(),
attr_path,
2019-09-06 16:55:58 +00:00
is_macro_use,
2019-03-13 13:38:02 +00:00
});
self.process_module(Some(item), item_list);
self.push_item(current_module, attrs, RawItemKind::Module(item));
2019-03-13 13:38:02 +00:00
return;
}
2019-03-13 13:38:02 +00:00
tested_by!(name_res_works_for_broken_modules);
}
2019-07-19 07:43:01 +00:00
fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
// FIXME: cfg_attr
let is_prelude = use_item.has_atom_attr("prelude_import");
let attrs = self.parse_attrs(&use_item);
Path::expand_use_item(
Source { ast: use_item, file_id: self.file_id },
self.db,
|path, use_tree, is_glob, alias| {
let import_data = ImportData {
path,
alias,
is_glob,
is_prelude,
is_extern_crate: false,
is_macro_use: false,
};
self.push_import(
current_module,
attrs.clone(),
import_data,
Either::A(AstPtr::new(use_tree)),
);
},
)
}
fn add_extern_crate_item(
&mut self,
current_module: Option<Module>,
2019-07-19 07:43:01 +00:00
extern_crate: ast::ExternCrateItem,
) {
if let Some(name_ref) = extern_crate.name_ref() {
2019-07-19 07:43:01 +00:00
let path = Path::from_name_ref(&name_ref);
let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
let attrs = self.parse_attrs(&extern_crate);
// FIXME: cfg_attr
let is_macro_use = extern_crate.has_atom_attr("macro_use");
2019-04-02 14:58:04 +00:00
let import_data = ImportData {
path,
alias,
is_glob: false,
is_prelude: false,
is_extern_crate: true,
is_macro_use,
2019-04-02 14:58:04 +00:00
};
self.push_import(
current_module,
attrs,
import_data,
Either::B(AstPtr::new(&extern_crate)),
);
}
}
2019-07-19 07:43:01 +00:00
fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
let attrs = self.parse_attrs(&m);
let path = match m
.path()
.and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db))
{
Some(it) => it,
_ => return,
};
let name = m.name().map(|it| it.as_name());
2019-07-19 07:43:01 +00:00
let ast_id = self.source_ast_id_map.ast_id(&m);
// FIXME: cfg_attr
2019-09-29 21:15:03 +00:00
let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
2019-03-26 15:03:17 +00:00
let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
self.push_item(current_module, attrs, RawItemKind::Macro(m));
}
2019-04-02 14:58:04 +00:00
fn push_import(
&mut self,
current_module: Option<Module>,
attrs: Arc<[Attr]>,
2019-04-02 14:58:04 +00:00
data: ImportData,
source: ImportSourcePtr,
) {
let import = self.raw_items.imports.alloc(data);
self.source_map.insert(import, source);
self.push_item(current_module, attrs, RawItemKind::Import(import))
2019-04-02 14:58:04 +00:00
}
fn push_item(&mut self, current_module: Option<Module>, attrs: Arc<[Attr]>, kind: RawItemKind) {
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(RawItem { attrs, kind })
}
fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Arc<[Attr]> {
2019-09-30 09:47:17 +00:00
Attr::from_attrs_owner(self.file_id, item, self.db)
}
}
fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> {
module.attrs().into_iter().find_map(|attr| {
2019-09-29 21:15:03 +00:00
attr.as_simple_key_value().and_then(|(name, value)| {
let is_path = name == "path";
if is_path {
Some(value)
} else {
None
}
})
})
}