pub mod mod_path;
mod fixup;
-pub use mbe::{ExpandError, ExpandResult, Origin};
+pub use mbe::{Origin, ValueResult};
-use std::{hash::Hash, iter, sync::Arc};
+use std::{fmt, hash::Hash, iter, sync::Arc};
use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange, ProcMacroKind};
use either::Either;
proc_macro::ProcMacroExpander,
};
+pub type ExpandResult<T> = ValueResult<T, ExpandError>;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum ExpandError {
+ UnresolvedProcMacro,
+ Mbe(mbe::ExpandError),
+ Other(Box<str>),
+}
+
+impl From<mbe::ExpandError> for ExpandError {
+ fn from(mbe: mbe::ExpandError) -> Self {
+ Self::Mbe(mbe)
+ }
+}
+
+impl fmt::Display for ExpandError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ExpandError::UnresolvedProcMacro => f.write_str("unresolved proc-macro"),
+ ExpandError::Mbe(it) => it.fmt(f),
+ ExpandError::Other(it) => f.write_str(it),
+ }
+ }
+}
+
/// 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
},
Derive {
ast_id: AstId<ast::Adt>,
- derive_name: Box<str>,
/// Syntactical index of the invoking `#[derive]` attribute.
///
/// Outer attributes are counted first, then inner attributes. This does not support
/// out-of-line modules, which may have attributes spread across 2 files!
derive_attr_index: u32,
+ /// Index of the derive macro in the derive attribute
+ derive_index: u32,
},
Attr {
ast_id: AstId<ast::Item>,
- attr_name: Box<str>,
- attr_args: (tt::Subtree, mbe::TokenMap),
+ attr_args: Arc<(tt::Subtree, mbe::TokenMap)>,
/// Syntactical index of the invoking `#[attribute]`.
///
/// Outer attributes are counted first, then inner attributes. This does not support
attr_input_or_mac_def: Option<InFile<ast::TokenTree>>,
macro_def: Arc<TokenExpander>,
- macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupMap)>,
+ macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
/// A shift built from `macro_arg`'s subtree, relevant for attributes as the item is the macro arg
/// and as such we need to shift tokens if they are part of an attributes input instead of their item.
macro_arg_shift: mbe::Shift,
let token_range = token.value.text_range();
match &loc.kind {
- MacroCallKind::Attr { attr_args: (_, map), invoc_attr_index, .. } => {
+ MacroCallKind::Attr { attr_args, invoc_attr_index, .. } => {
let attr = item
.doc_comments_and_attrs()
.nth(*invoc_attr_index as usize)
let relative_range =
token.value.text_range().checked_sub(attr_input_start)?;
// shift by the item's tree's max id
- let token_id =
- self.macro_arg_shift.shift(map.token_by_range(relative_range)?);
+ let token_id = self
+ .macro_arg_shift
+ .shift(attr_args.1.token_by_range(relative_range)?);
Some(token_id)
}
_ => None,
// Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item.
let (token_map, tt) = match &loc.kind {
- MacroCallKind::Attr { attr_args: (_, arg_token_map), .. } => {
+ MacroCallKind::Attr { attr_args, .. } => {
// try unshifting the the token id, if unshifting fails, the token resides in the non-item attribute input
// note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this
match self.macro_arg_shift.unshift(token_id) {
Some(unshifted) => {
token_id = unshifted;
- (arg_token_map, self.attr_input_or_mac_def.clone()?.syntax().cloned())
+ (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
}
None => (&self.macro_arg.1, self.arg.clone()),
}
expansion: &ExpansionInfo,
token: InFile<SyntaxToken>,
) -> Option<InFile<SyntaxToken>> {
- let (mapped, origin) = expansion.map_token_up(db, token.as_ref())?;
- if origin != Origin::Call {
- return None;
- }
- if let Some(info) = mapped.file_id.expansion_info(db) {
- return ascend_call_token(db, &info, mapped);
+ let mut mapping = expansion.map_token_up(db, token.as_ref())?;
+ while let (mapped, Origin::Call) = mapping {
+ match mapped.file_id.expansion_info(db) {
+ Some(info) => mapping = info.map_token_up(db, mapped.as_ref())?,
+ None => return Some(mapped),
+ }
}
- Some(mapped)
+ None
}
impl InFile<SyntaxToken> {
MACRO_TYPE => ExpandTo::Type,
ARG_LIST | TRY_EXPR | TUPLE_EXPR | PAREN_EXPR | ARRAY_EXPR | FOR_EXPR | PATH_EXPR
- | CLOSURE_EXPR | CONDITION | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM
- | MATCH_GUARD | RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR
- | FIELD_EXPR | AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR
- | BIN_EXPR => ExpandTo::Expr,
+ | CLOSURE_EXPR | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM | MATCH_GUARD
+ | RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR | FIELD_EXPR
+ | AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR
+ | LET_EXPR => ExpandTo::Expr,
LET_STMT => {
// FIXME: Handle LHS Pattern
ExpandTo::Expr