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

246 lines
8.1 KiB
Rust
Raw Normal View History

use std::sync::Arc;
use ra_syntax::{
2019-01-23 15:26:02 +00:00
SyntaxKind, AstNode, SourceFile, TreeArc, AstPtr,
2019-01-23 16:49:11 +00:00
ast::{self, ModuleItemOwner, NameOwner},
};
2019-01-18 13:36:56 +00:00
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
2019-01-23 16:49:11 +00:00
use rustc_hash::FxHashMap;
use crate::{
2019-01-18 13:56:02 +00:00
SourceItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems,
2019-01-24 12:28:50 +00:00
HirFileId, MacroCallLoc, AsName, PerNs, DefKind, DefLoc, Function,
2019-01-24 14:54:18 +00:00
ModuleDef, Module, Struct,
};
2019-01-18 13:36:56 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2019-01-18 13:56:02 +00:00
pub struct ImportId(RawId);
impl_arena_id!(ImportId);
2019-01-18 13:36:56 +00:00
#[derive(Debug, PartialEq, Eq)]
pub(super) struct ImportData {
pub(super) path: Path,
pub(super) is_glob: bool,
}
2019-01-18 13:56:02 +00:00
/// A set of items and imports declared inside a module, without relation to
/// other modules.
///
/// This sits in-between raw syntax and name resolution and allows us to avoid
/// recomputing name res: if two instance of `InputModuleItems` are the same, we
/// can avoid redoing name resolution.
2019-01-18 13:36:56 +00:00
#[derive(Debug, Default, PartialEq, Eq)]
pub struct LoweredModule {
pub(crate) declarations: FxHashMap<Name, PerNs<ModuleDef>>,
2019-01-18 13:56:02 +00:00
pub(super) imports: Arena<ImportId, ImportData>,
2019-01-18 13:36:56 +00:00
}
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportSourceMap {
2019-01-23 15:26:02 +00:00
map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
2019-01-18 13:36:56 +00:00
}
impl ImportSourceMap {
2019-01-18 13:56:02 +00:00
fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
2019-01-23 15:26:02 +00:00
self.map.insert(import, AstPtr::new(segment))
2019-01-18 13:36:56 +00:00
}
2019-01-18 13:56:02 +00:00
pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
2019-01-18 13:36:56 +00:00
let file = match source {
ModuleSource::SourceFile(file) => &*file,
ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
};
2019-01-23 15:26:02 +00:00
self.map[import].to_node(file).to_owned()
2019-01-18 13:36:56 +00:00
}
}
impl LoweredModule {
pub(crate) fn lower_module_module_query(
db: &impl HirDatabase,
module: Module,
2019-01-18 13:36:56 +00:00
) -> Arc<LoweredModule> {
db.lower_module(module).0
2019-01-18 13:36:56 +00:00
}
pub(crate) fn lower_module_source_map_query(
db: &impl HirDatabase,
module: Module,
2019-01-18 13:36:56 +00:00
) -> Arc<ImportSourceMap> {
db.lower_module(module).1
2019-01-18 13:36:56 +00:00
}
pub(crate) fn lower_module_query(
db: &impl HirDatabase,
module: Module,
2019-01-18 13:36:56 +00:00
) -> (Arc<LoweredModule>, Arc<ImportSourceMap>) {
let (file_id, source) = module.definition_source(db);
let file_id: HirFileId = file_id.into();
2019-01-18 13:36:56 +00:00
let mut source_map = ImportSourceMap::default();
let mut res = LoweredModule::default();
match source {
ModuleSource::SourceFile(it) => res.fill(
&mut source_map,
db,
module,
2019-01-18 13:36:56 +00:00
file_id,
&mut it.items_with_macros(),
),
ModuleSource::Module(it) => {
if let Some(item_list) = it.item_list() {
res.fill(
&mut source_map,
db,
module,
2019-01-18 13:36:56 +00:00
file_id,
&mut item_list.items_with_macros(),
)
}
}
};
(Arc::new(res), Arc::new(source_map))
}
fn fill(
&mut self,
source_map: &mut ImportSourceMap,
db: &impl HirDatabase,
module: Module,
2019-01-18 13:36:56 +00:00
file_id: HirFileId,
items: &mut Iterator<Item = ast::ItemOrMacro>,
) {
let file_items = db.file_items(file_id);
for item in items {
match item {
ast::ItemOrMacro::Item(it) => {
self.add_def_id(source_map, db, module, file_id, &file_items, it);
2019-01-18 13:36:56 +00:00
}
ast::ItemOrMacro::Macro(macro_call) => {
let item_id = file_items.id_of_unchecked(macro_call.syntax());
let loc = MacroCallLoc {
module,
2019-01-18 13:36:56 +00:00
source_item_id: SourceItemId {
file_id,
item_id: Some(item_id),
},
};
let id = loc.id(db);
let file_id = HirFileId::from(id);
let file_items = db.file_items(file_id);
//FIXME: expand recursively
for item in db.hir_source_file(file_id).items() {
self.add_def_id(source_map, db, module, file_id, &file_items, item);
2019-01-18 13:36:56 +00:00
}
}
}
}
}
2019-01-23 16:49:11 +00:00
fn add_def_id(
2019-01-18 13:36:56 +00:00
&mut self,
source_map: &mut ImportSourceMap,
2019-01-23 16:49:11 +00:00
db: &impl HirDatabase,
module: Module,
2019-01-18 13:36:56 +00:00
file_id: HirFileId,
file_items: &SourceFileItems,
item: &ast::ModuleItem,
2019-01-23 16:49:11 +00:00
) {
let name = match item.kind() {
2019-01-24 14:54:18 +00:00
ast::ModuleItemKind::StructDef(it) => {
if let Some(name) = it.name() {
let s = Struct::from_ast(db, module, file_id, it);
let s: ModuleDef = s.into();
self.declarations.insert(name.as_name(), PerNs::both(s, s));
}
return;
}
2019-01-23 16:49:11 +00:00
ast::ModuleItemKind::EnumDef(it) => it.name(),
2019-01-24 12:28:50 +00:00
ast::ModuleItemKind::FnDef(it) => {
if let Some(name) = it.name() {
let func = Function::from_ast(db, module, file_id, it);
self.declarations
.insert(name.as_name(), PerNs::values(func.into()));
}
return;
}
2019-01-23 16:49:11 +00:00
ast::ModuleItemKind::TraitDef(it) => it.name(),
ast::ModuleItemKind::TypeDef(it) => it.name(),
2019-01-18 13:36:56 +00:00
ast::ModuleItemKind::ImplBlock(_) => {
// impls don't define items
2019-01-23 16:49:11 +00:00
return;
}
ast::ModuleItemKind::UseItem(it) => {
self.add_use_item(source_map, it);
return;
2019-01-18 13:36:56 +00:00
}
ast::ModuleItemKind::ExternCrateItem(_) => {
// TODO
2019-01-23 16:49:11 +00:00
return;
2019-01-18 13:36:56 +00:00
}
2019-01-23 16:49:11 +00:00
ast::ModuleItemKind::ConstDef(it) => it.name(),
ast::ModuleItemKind::StaticDef(it) => it.name(),
ast::ModuleItemKind::Module(_) => {
// modules are handled separately direclty by nameres
return;
2019-01-18 13:36:56 +00:00
}
2019-01-23 16:49:11 +00:00
};
if let Some(name) = name {
let def_id = assign_def_id(db, module, file_id, file_items, item);
2019-01-23 16:49:11 +00:00
self.declarations.insert(name.as_name(), def_id);
2019-01-18 13:36:56 +00:00
}
}
fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
Path::expand_use_item(item, |path, segment| {
let import = self.imports.alloc(ImportData {
path,
is_glob: segment.is_none(),
});
if let Some(segment) = segment {
source_map.insert(import, segment)
}
})
}
}
2019-01-23 16:49:11 +00:00
fn assign_def_id(
db: &impl HirDatabase,
module: Module,
2019-01-23 16:49:11 +00:00
file_id: HirFileId,
file_items: &SourceFileItems,
item: &ast::ModuleItem,
) -> PerNs<ModuleDef> {
2019-01-23 16:49:11 +00:00
// depending on the item kind, the location can define something in
// the values namespace, the types namespace, or both
let kind = DefKind::for_syntax_kind(item.syntax().kind());
let def_id = kind.map(|k| {
let item_id = file_items.id_of_unchecked(item.syntax());
let def_loc = DefLoc {
kind: k,
module,
2019-01-23 16:49:11 +00:00
source_item_id: SourceItemId {
file_id,
item_id: Some(item_id),
},
};
def_loc.id(db).into()
2019-01-23 16:49:11 +00:00
});
def_id
}
impl DefKind {
fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
match kind {
2019-01-24 12:28:50 +00:00
SyntaxKind::FN_DEF => unreachable!(),
2019-01-23 16:49:11 +00:00
SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor),
SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum),
SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Trait),
SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Type),
SyntaxKind::CONST_DEF => PerNs::values(DefKind::Const),
SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Static),
_ => PerNs::none(),
}
}
}