From b7aa4898e0841ab8199643f89a0caa967b698ca8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 16:26:29 +0200 Subject: Rename ra_hir_expand -> hir_expand --- crates/ra_hir_expand/src/lib.rs | 453 ---------------------------------------- 1 file changed, 453 deletions(-) delete mode 100644 crates/ra_hir_expand/src/lib.rs (limited to 'crates/ra_hir_expand/src/lib.rs') diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs deleted file mode 100644 index 7425b561a..000000000 --- a/crates/ra_hir_expand/src/lib.rs +++ /dev/null @@ -1,453 +0,0 @@ -//! `ra_hir_expand` deals with macro expansion. -//! -//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax -//! tree originates not from the text of some `FileId`, but from some macro -//! expansion. - -pub mod db; -pub mod ast_id_map; -pub mod name; -pub mod hygiene; -pub mod diagnostics; -pub mod builtin_derive; -pub mod builtin_macro; -pub mod proc_macro; -pub mod quote; -pub mod eager; - -use std::hash::Hash; -use std::sync::Arc; - -use base_db::{impl_intern_key, salsa, CrateId, FileId}; -use syntax::{ - algo, - ast::{self, AstNode}, - SyntaxNode, SyntaxToken, TextSize, -}; - -use crate::ast_id_map::FileAstId; -use crate::builtin_derive::BuiltinDeriveExpander; -use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; -use crate::proc_macro::ProcMacroExpander; - -#[cfg(test)] -mod test_db; - -/// Input to the analyzer is a set of files, where each file is identified by -/// `FileId` and contains source code. However, another source of source code in -/// Rust are macros: each macro can be thought of as producing a "temporary -/// file". To assign an id to such a file, we use the id of the macro call that -/// produced the file. So, a `HirFileId` is either a `FileId` (source code -/// written by user), or a `MacroCallId` (source code produced by macro). -/// -/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file -/// containing the call plus the offset of the macro call in the file. Note that -/// this is a recursive definition! However, the size_of of `HirFileId` is -/// finite (because everything bottoms out at the real `FileId`) and small -/// (`MacroCallId` uses the location interning. You can check details here: -/// https://en.wikipedia.org/wiki/String_interning). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HirFileId(HirFileIdRepr); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum HirFileIdRepr { - FileId(FileId), - MacroFile(MacroFile), -} - -impl From for HirFileId { - fn from(id: FileId) -> Self { - HirFileId(HirFileIdRepr::FileId(id)) - } -} - -impl From for HirFileId { - fn from(id: MacroFile) -> Self { - HirFileId(HirFileIdRepr::MacroFile(id)) - } -} - -impl HirFileId { - /// For macro-expansion files, returns the file original source file the - /// expansion originated from. - pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId { - match self.0 { - HirFileIdRepr::FileId(file_id) => file_id, - HirFileIdRepr::MacroFile(macro_file) => { - let file_id = match macro_file.macro_call_id { - MacroCallId::LazyMacro(id) => { - let loc = db.lookup_intern_macro(id); - loc.kind.file_id() - } - MacroCallId::EagerMacro(id) => { - let loc = db.lookup_intern_eager_expansion(id); - loc.file_id - } - }; - file_id.original_file(db) - } - } - } - - pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 { - let mut level = 0; - let mut curr = self; - while let HirFileIdRepr::MacroFile(macro_file) = curr.0 { - level += 1; - curr = match macro_file.macro_call_id { - MacroCallId::LazyMacro(id) => { - let loc = db.lookup_intern_macro(id); - loc.kind.file_id() - } - MacroCallId::EagerMacro(id) => { - let loc = db.lookup_intern_eager_expansion(id); - loc.file_id - } - }; - } - level - } - - /// If this is a macro call, returns the syntax node of the call. - pub fn call_node(self, db: &dyn db::AstDatabase) -> Option> { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let lazy_id = match macro_file.macro_call_id { - MacroCallId::LazyMacro(id) => id, - MacroCallId::EagerMacro(_id) => { - // FIXME: handle call node for eager macro - return None; - } - }; - let loc = db.lookup_intern_macro(lazy_id); - Some(loc.kind.node(db)) - } - } - } - - /// Return expansion information if it is a macro-expansion file - pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let lazy_id = match macro_file.macro_call_id { - MacroCallId::LazyMacro(id) => id, - MacroCallId::EagerMacro(_id) => { - // FIXME: handle expansion_info for eager macro - return None; - } - }; - let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); - - let arg_tt = loc.kind.arg(db)?; - let def_tt = loc.def.ast_id?.to_node(db).token_tree()?; - - let macro_def = db.macro_def(loc.def)?; - let (parse, exp_map) = db.parse_macro(macro_file)?; - let macro_arg = db.macro_arg(macro_file.macro_call_id)?; - - Some(ExpansionInfo { - expanded: InFile::new(self, parse.syntax_node()), - arg: InFile::new(loc.kind.file_id(), arg_tt), - def: InFile::new(loc.def.ast_id?.file_id, def_tt), - macro_arg, - macro_def, - exp_map, - }) - } - } - } - - /// Indicate it is macro file generated for builtin derive - pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option> { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let lazy_id = match macro_file.macro_call_id { - MacroCallId::LazyMacro(id) => id, - MacroCallId::EagerMacro(_id) => { - return None; - } - }; - let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); - let item = match loc.def.kind { - MacroDefKind::BuiltInDerive(_) => loc.kind.node(db), - _ => return None, - }; - Some(item.with_value(ast::Item::cast(item.value.clone())?)) - } - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroFile { - macro_call_id: MacroCallId, -} - -/// `MacroCallId` identifies a particular macro invocation, like -/// `println!("Hello, {}", world)`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MacroCallId { - LazyMacro(LazyMacroId), - EagerMacro(EagerMacroId), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct LazyMacroId(salsa::InternId); -impl_intern_key!(LazyMacroId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EagerMacroId(salsa::InternId); -impl_intern_key!(EagerMacroId); - -impl From for MacroCallId { - fn from(it: LazyMacroId) -> Self { - MacroCallId::LazyMacro(it) - } -} -impl From for MacroCallId { - fn from(it: EagerMacroId) -> Self { - MacroCallId::EagerMacro(it) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroDefId { - // FIXME: krate and ast_id are currently optional because we don't have a - // definition location for built-in derives. There is one, though: the - // standard library defines them. The problem is that it uses the new - // `macro` syntax for this, which we don't support yet. As soon as we do - // (which will probably require touching this code), we can instead use - // that (and also remove the hacks for resolving built-in derives). - pub krate: Option, - pub ast_id: Option>, - pub kind: MacroDefKind, - - pub local_inner: bool, -} - -impl MacroDefId { - pub fn as_lazy_macro( - self, - db: &dyn db::AstDatabase, - krate: CrateId, - kind: MacroCallKind, - ) -> LazyMacroId { - db.intern_macro(MacroCallLoc { def: self, krate, kind }) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MacroDefKind { - Declarative, - BuiltIn(BuiltinFnLikeExpander), - // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander - BuiltInDerive(BuiltinDeriveExpander), - BuiltInEager(EagerExpander), - CustomDerive(ProcMacroExpander), -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroCallLoc { - pub(crate) def: MacroDefId, - pub(crate) krate: CrateId, - pub(crate) kind: MacroCallKind, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum MacroCallKind { - FnLike(AstId), - Attr(AstId, String), -} - -impl MacroCallKind { - fn file_id(&self) -> HirFileId { - match self { - MacroCallKind::FnLike(ast_id) => ast_id.file_id, - MacroCallKind::Attr(ast_id, _) => ast_id.file_id, - } - } - - fn node(&self, db: &dyn db::AstDatabase) -> InFile { - match self { - MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), - MacroCallKind::Attr(ast_id, _) => { - ast_id.with_value(ast_id.to_node(db).syntax().clone()) - } - } - } - - fn arg(&self, db: &dyn db::AstDatabase) -> Option { - match self { - MacroCallKind::FnLike(ast_id) => { - Some(ast_id.to_node(db).token_tree()?.syntax().clone()) - } - MacroCallKind::Attr(ast_id, _) => Some(ast_id.to_node(db).syntax().clone()), - } - } -} - -impl MacroCallId { - pub fn as_file(self) -> HirFileId { - MacroFile { macro_call_id: self }.into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct EagerCallLoc { - pub(crate) def: MacroDefId, - pub(crate) fragment: FragmentKind, - pub(crate) subtree: Arc, - pub(crate) krate: CrateId, - pub(crate) file_id: HirFileId, -} - -/// ExpansionInfo mainly describes how to map text range between src and expanded macro -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExpansionInfo { - expanded: InFile, - arg: InFile, - def: InFile, - - macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, - macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, - exp_map: Arc, -} - -pub use mbe::Origin; -use parser::FragmentKind; - -impl ExpansionInfo { - pub fn call_node(&self) -> Option> { - Some(self.arg.with_value(self.arg.value.parent()?)) - } - - pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option> { - assert_eq!(token.file_id, self.arg.file_id); - let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; - let token_id = self.macro_arg.1.token_by_range(range)?; - let token_id = self.macro_def.0.map_id_down(token_id); - - let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?; - - let token = algo::find_covering_element(&self.expanded.value, range).into_token()?; - - Some(self.expanded.with_value(token)) - } - - pub fn map_token_up( - &self, - token: InFile<&SyntaxToken>, - ) -> Option<(InFile, Origin)> { - let token_id = self.exp_map.token_by_range(token.value.text_range())?; - - let (token_id, origin) = self.macro_def.0.map_id_up(token_id); - let (token_map, tt) = match origin { - mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), - mbe::Origin::Def => { - (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone())) - } - }; - - let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; - let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) - .into_token()?; - Some((tt.with_value(token), origin)) - } -} - -/// `AstId` points to an AST node in any file. -/// -/// It is stable across reparses, and can be used as salsa key/value. -// FIXME: isn't this just a `Source>` ? -pub type AstId = InFile>; - -impl AstId { - pub fn to_node(&self, db: &dyn db::AstDatabase) -> N { - let root = db.parse_or_expand(self.file_id).unwrap(); - db.ast_id_map(self.file_id).get(self.value).to_node(&root) - } -} - -/// `InFile` stores a value of `T` inside a particular file/syntax tree. -/// -/// Typical usages are: -/// -/// * `InFile` -- syntax node in a file -/// * `InFile` -- ast node in a file -/// * `InFile` -- offset in a file -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct InFile { - pub file_id: HirFileId, - pub value: T, -} - -impl InFile { - pub fn new(file_id: HirFileId, value: T) -> InFile { - InFile { file_id, value } - } - - // Similarly, naming here is stupid... - pub fn with_value(&self, value: U) -> InFile { - InFile::new(self.file_id, value) - } - - pub fn map U, U>(self, f: F) -> InFile { - InFile::new(self.file_id, f(self.value)) - } - pub fn as_ref(&self) -> InFile<&T> { - self.with_value(&self.value) - } - pub fn file_syntax(&self, db: &dyn db::AstDatabase) -> SyntaxNode { - db.parse_or_expand(self.file_id).expect("source created from invalid file") - } -} - -impl InFile<&T> { - pub fn cloned(&self) -> InFile { - self.with_value(self.value.clone()) - } -} - -impl InFile> { - pub fn transpose(self) -> Option> { - let value = self.value?; - Some(InFile::new(self.file_id, value)) - } -} - -impl InFile { - pub fn ancestors_with_macros( - self, - db: &dyn db::AstDatabase, - ) -> impl Iterator> + '_ { - std::iter::successors(Some(self), move |node| match node.value.parent() { - Some(parent) => Some(node.with_value(parent)), - None => { - let parent_node = node.file_id.call_node(db)?; - Some(parent_node) - } - }) - } -} - -impl InFile { - pub fn ancestors_with_macros( - self, - db: &dyn db::AstDatabase, - ) -> impl Iterator> + '_ { - self.map(|it| it.parent()).ancestors_with_macros(db) - } -} - -impl InFile { - pub fn descendants(self) -> impl Iterator> { - self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n)) - } - - pub fn syntax(&self) -> InFile<&SyntaxNode> { - self.with_value(self.value.syntax()) - } -} -- cgit v1.2.3