2018-11-27 18:42:26 -06:00
|
|
|
//! HIR (previsouly known as descriptors) provides a high-level OO acess to Rust
|
|
|
|
//! code.
|
|
|
|
//!
|
|
|
|
//! The principal difference between HIR and syntax trees is that HIR is bound
|
|
|
|
//! to a particular crate instance. That is, it has cfg flags and features
|
|
|
|
//! applied. So, there relation between syntax and HIR is many-to-one.
|
|
|
|
|
|
|
|
macro_rules! ctry {
|
|
|
|
($expr:expr) => {
|
|
|
|
match $expr {
|
|
|
|
None => return Ok(None),
|
|
|
|
Some(it) => it,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-11-27 19:09:44 -06:00
|
|
|
pub mod db;
|
2018-11-28 07:19:01 -06:00
|
|
|
#[cfg(test)]
|
|
|
|
mod mock;
|
2018-11-27 18:42:26 -06:00
|
|
|
mod query_definitions;
|
|
|
|
mod path;
|
|
|
|
mod arena;
|
2018-12-05 04:16:20 -06:00
|
|
|
pub mod source_binder;
|
2018-11-27 18:42:26 -06:00
|
|
|
|
2018-12-31 07:05:07 -06:00
|
|
|
mod macros;
|
2018-12-27 11:07:21 -06:00
|
|
|
mod name;
|
2018-12-08 14:40:55 -06:00
|
|
|
mod krate;
|
|
|
|
mod module;
|
|
|
|
mod function;
|
2018-12-24 12:07:48 -06:00
|
|
|
mod adt;
|
2018-12-25 14:14:13 -06:00
|
|
|
mod type_ref;
|
2018-12-20 14:56:28 -06:00
|
|
|
mod ty;
|
2018-12-08 14:40:55 -06:00
|
|
|
|
2018-11-27 18:42:26 -06:00
|
|
|
use std::ops::Index;
|
|
|
|
|
2019-01-01 10:51:11 -06:00
|
|
|
use ra_syntax::{SyntaxNodeRef, SyntaxNode, SyntaxKind, SourceFile, AstNode, ast};
|
2018-11-27 18:42:26 -06:00
|
|
|
use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable};
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
db::HirDatabase,
|
|
|
|
arena::{Arena, Id},
|
2018-12-27 11:26:15 -06:00
|
|
|
name::{AsName, KnownName},
|
2018-11-27 18:42:26 -06:00
|
|
|
};
|
|
|
|
|
2018-11-27 19:09:44 -06:00
|
|
|
pub use self::{
|
2018-11-27 18:42:26 -06:00
|
|
|
path::{Path, PathKind},
|
2018-12-27 11:07:21 -06:00
|
|
|
name::Name,
|
2018-12-08 14:40:55 -06:00
|
|
|
krate::Crate,
|
2019-01-01 09:12:31 -06:00
|
|
|
macros::{MacroDef, MacroInput, MacroExpansion, MacroCallId, MacroCallLoc},
|
2018-12-24 13:32:39 -06:00
|
|
|
module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
|
2018-11-27 18:42:26 -06:00
|
|
|
function::{Function, FnScopes},
|
2018-12-24 12:07:48 -06:00
|
|
|
adt::{Struct, Enum},
|
2018-12-25 08:15:40 -06:00
|
|
|
ty::Ty,
|
2018-11-27 18:42:26 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
pub use self::function::FnSignatureInfo;
|
|
|
|
|
2019-01-01 11:19:24 -06:00
|
|
|
/// An `MFileId` is like a `FileId`, but it can also refer to code generated by
|
|
|
|
/// macros.
|
|
|
|
pub enum MFileId {
|
|
|
|
File(FileId),
|
|
|
|
Macro(MacroCallId),
|
|
|
|
}
|
|
|
|
|
2018-12-04 14:52:14 -06:00
|
|
|
/// Def's are a core concept of hir. A `Def` is an Item (function, module, etc)
|
|
|
|
/// in a specific module.
|
2018-11-27 18:42:26 -06:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
2018-11-27 19:09:44 -06:00
|
|
|
pub struct DefId(u32);
|
2018-11-27 18:42:26 -06:00
|
|
|
ra_db::impl_numeric_id!(DefId);
|
|
|
|
|
2018-12-04 14:01:53 -06:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub(crate) enum DefKind {
|
|
|
|
Module,
|
2018-12-04 14:44:00 -06:00
|
|
|
Function,
|
2018-12-24 12:07:48 -06:00
|
|
|
Struct,
|
|
|
|
Enum,
|
2018-12-04 14:01:53 -06:00
|
|
|
Item,
|
2018-12-24 13:32:39 -06:00
|
|
|
|
|
|
|
StructCtor,
|
2018-12-04 14:01:53 -06:00
|
|
|
}
|
|
|
|
|
2018-11-27 18:42:26 -06:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
2018-12-04 14:01:53 -06:00
|
|
|
pub struct DefLoc {
|
|
|
|
pub(crate) kind: DefKind,
|
|
|
|
source_root_id: SourceRootId,
|
|
|
|
module_id: ModuleId,
|
|
|
|
source_item_id: SourceItemId,
|
2018-11-27 18:42:26 -06:00
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
impl DefKind {
|
2018-12-24 13:32:39 -06:00
|
|
|
pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
|
2018-12-23 10:13:11 -06:00
|
|
|
match kind {
|
2018-12-24 13:32:39 -06:00
|
|
|
SyntaxKind::FN_DEF => PerNs::values(DefKind::Function),
|
|
|
|
SyntaxKind::MODULE => PerNs::types(DefKind::Module),
|
|
|
|
SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor),
|
|
|
|
SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum),
|
2018-12-23 10:13:11 -06:00
|
|
|
// These define items, but don't have their own DefKinds yet:
|
2018-12-24 13:32:39 -06:00
|
|
|
SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Item),
|
|
|
|
SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Item),
|
|
|
|
SyntaxKind::CONST_DEF => PerNs::values(DefKind::Item),
|
|
|
|
SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Item),
|
|
|
|
_ => PerNs::none(),
|
2018-12-23 10:13:11 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-27 18:42:26 -06:00
|
|
|
impl DefId {
|
2018-12-04 14:52:14 -06:00
|
|
|
pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
|
2018-11-27 18:42:26 -06:00
|
|
|
db.as_ref().id2loc(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DefLoc {
|
2018-12-04 14:52:14 -06:00
|
|
|
pub(crate) fn id(&self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefId {
|
2018-11-27 18:42:26 -06:00
|
|
|
db.as_ref().loc2id(&self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-27 19:09:44 -06:00
|
|
|
pub enum Def {
|
2018-11-27 18:42:26 -06:00
|
|
|
Module(Module),
|
2018-12-04 14:44:00 -06:00
|
|
|
Function(Function),
|
2018-12-24 12:07:48 -06:00
|
|
|
Struct(Struct),
|
|
|
|
Enum(Enum),
|
2018-11-27 18:42:26 -06:00
|
|
|
Item,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DefId {
|
2018-11-27 19:09:44 -06:00
|
|
|
pub fn resolve(self, db: &impl HirDatabase) -> Cancelable<Def> {
|
2018-11-27 18:42:26 -06:00
|
|
|
let loc = self.loc(db);
|
2018-12-04 14:01:53 -06:00
|
|
|
let res = match loc.kind {
|
|
|
|
DefKind::Module => {
|
2018-12-04 14:52:14 -06:00
|
|
|
let module = Module::new(db, loc.source_root_id, loc.module_id)?;
|
|
|
|
Def::Module(module)
|
2018-11-27 18:42:26 -06:00
|
|
|
}
|
2018-12-04 14:52:14 -06:00
|
|
|
DefKind::Function => {
|
|
|
|
let function = Function::new(self);
|
|
|
|
Def::Function(function)
|
|
|
|
}
|
2018-12-24 12:07:48 -06:00
|
|
|
DefKind::Struct => {
|
|
|
|
let struct_def = Struct::new(self);
|
|
|
|
Def::Struct(struct_def)
|
|
|
|
}
|
|
|
|
DefKind::Enum => {
|
|
|
|
let enum_def = Enum::new(self);
|
|
|
|
Def::Enum(enum_def)
|
|
|
|
}
|
2018-12-24 13:32:39 -06:00
|
|
|
DefKind::StructCtor => Def::Item,
|
2018-12-04 14:52:14 -06:00
|
|
|
DefKind::Item => Def::Item,
|
2018-11-27 18:42:26 -06:00
|
|
|
};
|
|
|
|
Ok(res)
|
|
|
|
}
|
2018-12-25 06:31:30 -06:00
|
|
|
|
|
|
|
/// For a module, returns that module; for any other def, returns the containing module.
|
|
|
|
pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> {
|
|
|
|
let loc = self.loc(db);
|
|
|
|
Module::new(db, loc.source_root_id, loc.module_id)
|
|
|
|
}
|
2018-11-27 18:42:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Identifier of item within a specific file. This is stable over reparses, so
|
|
|
|
/// it's OK to use it as a salsa key/value.
|
|
|
|
pub(crate) type SourceFileItemId = Id<SyntaxNode>;
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
2018-11-27 19:09:44 -06:00
|
|
|
pub struct SourceItemId {
|
2018-11-27 18:42:26 -06:00
|
|
|
file_id: FileId,
|
2018-12-18 16:48:46 -06:00
|
|
|
/// None for the whole file.
|
|
|
|
item_id: Option<SourceFileItemId>,
|
2018-11-27 18:42:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Maps item's `SyntaxNode`s to `SourceFileItemId` and back.
|
2018-12-09 04:18:46 -06:00
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
2018-11-27 19:09:44 -06:00
|
|
|
pub struct SourceFileItems {
|
2018-12-09 04:18:46 -06:00
|
|
|
file_id: FileId,
|
2018-11-27 18:42:26 -06:00
|
|
|
arena: Arena<SyntaxNode>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SourceFileItems {
|
2019-01-01 10:51:11 -06:00
|
|
|
fn new(file_id: FileId, source_file: SourceFile) -> SourceFileItems {
|
|
|
|
let mut res = SourceFileItems {
|
2018-12-09 04:18:46 -06:00
|
|
|
file_id,
|
|
|
|
arena: Arena::default(),
|
2019-01-01 10:51:11 -06:00
|
|
|
};
|
|
|
|
res.init(source_file);
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init(&mut self, source_file: SourceFile) {
|
|
|
|
source_file.syntax().descendants().for_each(|it| {
|
|
|
|
if let Some(module_item) = ast::ModuleItem::cast(it) {
|
|
|
|
self.alloc(module_item.syntax().owned());
|
|
|
|
} else if let Some(macro_call) = ast::MacroCall::cast(it) {
|
|
|
|
self.alloc(macro_call.syntax().owned());
|
|
|
|
}
|
|
|
|
});
|
2018-12-09 04:18:46 -06:00
|
|
|
}
|
|
|
|
|
2018-11-27 18:42:26 -06:00
|
|
|
fn alloc(&mut self, item: SyntaxNode) -> SourceFileItemId {
|
|
|
|
self.arena.alloc(item)
|
|
|
|
}
|
2018-12-09 04:18:46 -06:00
|
|
|
pub fn id_of(&self, file_id: FileId, item: SyntaxNodeRef) -> SourceFileItemId {
|
|
|
|
assert_eq!(
|
|
|
|
self.file_id, file_id,
|
|
|
|
"SourceFileItems: wrong file, expected {:?}, got {:?}",
|
|
|
|
self.file_id, file_id
|
|
|
|
);
|
|
|
|
self.id_of_unchecked(item)
|
|
|
|
}
|
|
|
|
fn id_of_unchecked(&self, item: SyntaxNodeRef) -> SourceFileItemId {
|
2018-12-09 05:21:54 -06:00
|
|
|
if let Some((id, _)) = self.arena.iter().find(|(_id, i)| i.borrowed() == item) {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
// This should not happen. Let's try to give a sensible diagnostics.
|
2018-12-18 05:58:54 -06:00
|
|
|
if let Some((id, i)) = self.arena.iter().find(|(_id, i)| i.range() == item.range()) {
|
|
|
|
// FIXME(#288): whyyy are we getting here?
|
|
|
|
log::error!(
|
2018-12-09 05:21:54 -06:00
|
|
|
"unequal syntax nodes with the same range:\n{:?}\n{:?}",
|
2018-12-18 05:58:54 -06:00
|
|
|
item,
|
|
|
|
i
|
|
|
|
);
|
|
|
|
return id;
|
2018-12-09 05:21:54 -06:00
|
|
|
}
|
|
|
|
panic!(
|
|
|
|
"Can't find {:?} in SourceFileItems:\n{:?}",
|
|
|
|
item,
|
|
|
|
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
|
|
|
|
);
|
2018-11-27 18:42:26 -06:00
|
|
|
}
|
2018-12-04 13:46:23 -06:00
|
|
|
pub fn id_of_source_file(&self) -> SourceFileItemId {
|
|
|
|
let (id, _syntax) = self.arena.iter().next().unwrap();
|
|
|
|
id
|
|
|
|
}
|
2018-11-27 18:42:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<SourceFileItemId> for SourceFileItems {
|
|
|
|
type Output = SyntaxNode;
|
|
|
|
fn index(&self, idx: SourceFileItemId) -> &SyntaxNode {
|
|
|
|
&self.arena[idx]
|
|
|
|
}
|
|
|
|
}
|