pub mod proc_macro;
pub mod quote;
pub mod eager;
+pub mod mod_path;
use base_db::ProcMacroKind;
use either::Either;
pub use mbe::{ExpandError, ExpandResult, Origin};
+use mod_path::ModPath;
use std::{hash::Hash, iter, sync::Arc};
use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
use syntax::{
algo::{self, skip_trivia_token},
- ast::{self, AstNode, HasAttrs},
+ ast::{self, AstNode, HasDocComments},
Direction, SyntaxNode, SyntaxToken,
};
expand_to: ExpandTo,
},
Derive {
- ast_id: AstId<ast::Item>,
+ ast_id: AstId<ast::Adt>,
derive_name: Box<str>,
/// Syntactical index of the invoking `#[derive]` attribute.
///
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
let tt = ast_id
.to_node(db)
- .attrs()
- .nth(invoc_attr_index as usize)?
+ .doc_comments_and_attrs()
+ .nth(invoc_attr_index as usize)
+ .and_then(Either::left)?
.token_tree()?;
Some(InFile::new(ast_id.file_id, tt))
}
impl MacroCallKind {
/// Returns the file containing the macro invocation.
fn file_id(&self) -> HirFileId {
- match self {
- MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id,
- MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => {
- ast_id.file_id
- }
+ match *self {
+ MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. }
+ | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. }
+ | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id,
}
}
MacroCallKind::FnLike { ast_id, .. } => {
ast_id.with_value(ast_id.to_node(db).syntax().clone())
}
- MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => {
+ MacroCallKind::Derive { 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())
}
}
}
+ /// Returns the original file range that best describes the location of this macro call.
+ ///
+ /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
+ /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
+ /// get only the specific derive that is being referred to.
+ pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange {
+ let mut kind = self;
+ loop {
+ match kind.file_id().0 {
+ HirFileIdRepr::MacroFile(file) => {
+ kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
+ }
+ _ => break,
+ }
+ }
+
+ // `call_id` is now the outermost macro call, so its location is in a real file.
+ let file_id = match kind.file_id().0 {
+ HirFileIdRepr::FileId(it) => it,
+ HirFileIdRepr::MacroFile(_) => unreachable!("encountered unexpected macro file"),
+ };
+ let range = match kind {
+ MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
+ MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
+ // FIXME: should be the range of the macro name, not the whole derive
+ ast_id
+ .to_node(db)
+ .doc_comments_and_attrs()
+ .nth(derive_attr_index as usize)
+ .expect("missing derive")
+ .expect_left("derive is a doc comment?")
+ .syntax()
+ .text_range()
+ }
+ MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => ast_id
+ .to_node(db)
+ .doc_comments_and_attrs()
+ .nth(invoc_attr_index as usize)
+ .expect("missing attribute")
+ .expect_left("attribute macro is a doc comment?")
+ .syntax()
+ .text_range(),
+ };
+
+ FileRange { range, file_id }
+ }
+
fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
match self {
MacroCallKind::FnLike { ast_id, .. } => {
Some(ast_id.to_node(db).token_tree()?.syntax().clone())
}
- MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => {
- Some(ast_id.to_node(db).syntax().clone())
- }
+ MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
+ MacroCallKind::Attr { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
}
}
let token_range = token.value.text_range();
match &loc.kind {
- MacroCallKind::Attr { attr_args, invoc_attr_index, .. } => {
- let attr = item.attrs().nth(*invoc_attr_index as usize)?;
+ MacroCallKind::Attr { attr_args: (_, map), invoc_attr_index, .. } => {
+ let attr = item
+ .doc_comments_and_attrs()
+ .nth(*invoc_attr_index as usize)
+ .and_then(Either::left)?;
match attr.token_tree() {
Some(token_tree)
if token_tree.syntax().text_range().contains_range(token_range) =>
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(attr_args.1.token_by_range(relative_range)?);
+ let token_id =
+ self.macro_arg_shift.shift(map.token_by_range(relative_range)?);
Some(token_id)
}
_ => None,
) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
iter::successors(Some(self.cloned()), 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)
- }
+ None => node.file_id.call_node(db),
})
}
}
// Fall back to whole macro call.
- let mut node = self.cloned();
- while let Some(call_node) = node.file_id.call_node(db) {
- node = call_node;
+ match self.file_id.0 {
+ HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
+ HirFileIdRepr::MacroFile(mac_file) => {
+ let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
+ loc.kind.original_call_range(db)
+ }
}
-
- let orig_file = node.file_id.original_file(db);
- assert_eq!(node.file_id, orig_file.into());
-
- FileRange { file_id: orig_file, range: node.value.text_range() }
}
/// Attempts to map the syntax node back up its macro calls.
}
}
}
+
+#[derive(Debug)]
+pub struct UnresolvedMacro {
+ pub path: ModPath,
+}