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

406 lines
13 KiB
Rust
Raw Normal View History

//! FIXME: write short doc here
use std::{ops::Index, sync::Arc};
2019-10-30 15:56:20 +00:00
use hir_expand::{
ast_id_map::AstIdMap,
db::AstDatabase,
either::Either,
2019-10-30 16:10:53 +00:00
hygiene::Hygiene,
2019-10-30 15:56:20 +00:00
name::{AsName, Name},
};
use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
use ra_syntax::{
ast::{self, AttrsOwner, NameOwner},
2019-10-10 14:42:29 +00:00
AstNode, AstPtr, SourceFile,
};
2019-11-03 20:44:23 +00:00
use test_utils::tested_by;
2019-10-30 16:10:53 +00:00
use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, 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
2019-10-30 15:50:10 +00:00
fn to_node(ptr: ImportSourcePtr, file: &SourceFile) -> ImportSource {
ptr.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-10-30 13:12:55 +00:00
pub 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-10-30 15:50:10 +00:00
to_node(self.map[import], &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(
2019-10-30 13:12:55 +00:00
db: &(impl DefDatabase2 + AstDatabase),
2019-06-01 18:17:57 +00:00
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-10-30 13:12:55 +00:00
db: &(impl DefDatabase2 + 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,
hygiene: Hygiene::new(db, file_id),
};
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-11-08 20:47:52 +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]
}
}
2019-10-02 17:38:56 +00:00
// Avoid heap allocation on items without attributes.
2019-10-10 14:16:02 +00:00
type Attrs = Option<Arc<[Attr]>>;
2019-10-02 17:38:56 +00:00
#[derive(Debug, PartialEq, Eq, Clone)]
2019-11-08 21:23:11 +00:00
pub(super) struct RawItem {
2019-10-10 14:16:02 +00:00
attrs: Attrs,
2019-11-08 20:47:52 +00:00
pub(super) kind: RawItemKind,
}
2019-10-10 14:16:02 +00:00
impl RawItem {
2019-11-08 20:47:52 +00:00
pub(super) fn attrs(&self) -> &[Attr] {
2019-10-10 14:16:02 +00:00
self.attrs.as_ref().map_or(&[], |it| &*it)
}
}
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
2019-11-08 21:23:11 +00:00
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-11-08 21:23:11 +00:00
pub(super) struct Module(RawId);
impl_arena_id!(Module);
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq)]
2019-11-08 21:23:11 +00:00
pub(super) enum ModuleData {
2019-10-10 14:48:30 +00:00
Declaration { name: Name, ast_id: FileAstId<ast::Module> },
Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
}
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-11-08 20:47:52 +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-11-08 21:23:11 +00:00
pub(super) struct Def(RawId);
impl_arena_id!(Def);
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq)]
2019-11-08 21:23:11 +00:00
pub(super) struct DefData {
2019-11-08 20:47:52 +00:00
pub(super) name: Name,
pub(super) kind: DefKind,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
2019-11-08 21:23:11 +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-11-08 21:23:11 +00:00
pub(super) struct Macro(RawId);
impl_arena_id!(Macro);
2019-03-13 13:38:02 +00:00
#[derive(Debug, PartialEq, Eq)]
2019-11-08 21:23:11 +00:00
pub(super) struct MacroData {
2019-11-08 20:47:52 +00:00
pub(super) ast_id: FileAstId<ast::MacroCall>,
pub(super) path: Path,
pub(super) name: Option<Name>,
pub(super) export: bool,
2019-11-10 03:03:24 +00:00
pub(super) builtin: bool,
}
struct RawItemsCollector {
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,
hygiene: Hygiene,
}
impl RawItemsCollector {
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);
if module.has_semi() {
2019-10-10 14:48:30 +00:00
let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
self.push_item(current_module, attrs, RawItemKind::Module(item));
return;
}
if let Some(item_list) = module.item_list() {
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(),
});
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-11-03 20:44:23 +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);
let mut buf = Vec::new();
Path::expand_use_item(
Source { ast: use_item, file_id: self.file_id },
&self.hygiene,
|path, use_tree, is_glob, alias| {
let import_data = ImportData {
path,
alias,
is_glob,
is_prelude,
is_extern_crate: false,
is_macro_use: false,
};
buf.push((import_data, Either::A(AstPtr::new(use_tree))));
},
);
for (import_data, ptr) in buf {
self.push_import(current_module, attrs.clone(), import_data, ptr);
}
}
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(path, &self.hygiene)) {
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-11-10 03:03:24 +00:00
// FIXME: cfg_attr
let builtin =
m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro");
let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin });
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>,
2019-10-02 17:38:56 +00:00
attrs: Attrs,
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
}
2019-10-02 17:38:56 +00:00
fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, 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 })
}
2019-10-02 17:38:56 +00:00
fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
Attr::from_attrs_owner(item, &self.hygiene)
}
}