Add hygiene information to SourceAnalyzer

This commit is contained in:
Edwin Cheng 2019-11-26 15:05:53 +08:00
parent 58a3b3b502
commit 245a9b165a
5 changed files with 36 additions and 13 deletions

View file

@ -14,7 +14,8 @@ use hir_def::{
DefWithBodyId, DefWithBodyId,
}; };
use hir_expand::{ use hir_expand::{
name::AsName, AstId, HirFileId, MacroCallId, MacroCallLoc, MacroFileKind, Source, hygiene::Hygiene, name::AsName, AstId, HirFileId, MacroCallId, MacroCallLoc, MacroFileKind,
Source,
}; };
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
@ -236,10 +237,10 @@ impl SourceAnalyzer {
pub fn resolve_macro_call( pub fn resolve_macro_call(
&self, &self,
db: &impl HirDatabase, db: &impl HirDatabase,
macro_call: &ast::MacroCall, macro_call: Source<&ast::MacroCall>,
) -> Option<MacroDef> { ) -> Option<MacroDef> {
// This must be a normal source file rather than macro file. let hygiene = Hygiene::new(db, macro_call.file_id);
let path = macro_call.path().and_then(Path::from_ast)?; let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?;
self.resolver.resolve_path_as_macro(db, &path).map(|it| it.into()) self.resolver.resolve_path_as_macro(db, &path).map(|it| it.into())
} }
@ -441,12 +442,14 @@ impl SourceAnalyzer {
db: &impl HirDatabase, db: &impl HirDatabase,
macro_call: Source<&ast::MacroCall>, macro_call: Source<&ast::MacroCall>,
) -> Option<Expansion> { ) -> Option<Expansion> {
let def = self.resolve_macro_call(db, macro_call.value)?.id; let def = self.resolve_macro_call(db, macro_call)?.id;
let ast_id = AstId::new( let ast_id = AstId::new(
macro_call.file_id, macro_call.file_id,
db.ast_id_map(macro_call.file_id).ast_id(macro_call.value), db.ast_id_map(macro_call.file_id).ast_id(macro_call.value),
); );
let macro_call_loc = MacroCallLoc { def, ast_id }; let macro_call_loc = MacroCallLoc { def, ast_id };
let kind = to_macro_file_kind(macro_call.value);
dbg!(kind);
Some(Expansion { Some(Expansion {
macro_call_id: db.intern_macro(macro_call_loc), macro_call_id: db.intern_macro(macro_call_loc),
macro_file_kind: to_macro_file_kind(macro_call.value), macro_file_kind: to_macro_file_kind(macro_call.value),

View file

@ -97,7 +97,7 @@ impl Path {
/// Converts an `ast::Path` to `Path`. Works with use trees. /// Converts an `ast::Path` to `Path`. Works with use trees.
/// It correctly handles `$crate` based path from macro call. /// It correctly handles `$crate` based path from macro call.
pub(crate) fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
let mut kind = PathKind::Plain; let mut kind = PathKind::Plain;
let mut segments = Vec::new(); let mut segments = Vec::new();
loop { loop {

View file

@ -18,12 +18,9 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
// Find the calling expression and it's NameRef // Find the calling expression and it's NameRef
let calling_node = FnCallNode::with_node(&syntax, position.offset)?; let calling_node = FnCallNode::with_node(&syntax, position.offset)?;
let name_ref = calling_node.name_ref()?; let name_ref = calling_node.name_ref()?;
let name_ref = hir::Source::new(position.file_id.into(), name_ref.syntax());
let analyzer = hir::SourceAnalyzer::new( let analyzer = hir::SourceAnalyzer::new(db, name_ref, None);
db,
hir::Source::new(position.file_id.into(), name_ref.syntax()),
None,
);
let (mut call_info, has_self) = match &calling_node { let (mut call_info, has_self) = match &calling_node {
FnCallNode::CallExpr(expr) => { FnCallNode::CallExpr(expr) => {
//FIXME: don't poke into Ty //FIXME: don't poke into Ty
@ -44,7 +41,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
(CallInfo::with_fn(db, function), function.has_self_param(db)) (CallInfo::with_fn(db, function), function.has_self_param(db))
} }
FnCallNode::MacroCallExpr(expr) => { FnCallNode::MacroCallExpr(expr) => {
let macro_def = analyzer.resolve_macro_call(db, &expr)?; let macro_def = analyzer.resolve_macro_call(db, name_ref.with_value(&expr))?;
(CallInfo::with_macro(db, macro_def)?, false) (CallInfo::with_macro(db, macro_def)?, false)
} }
}; };

View file

@ -269,4 +269,27 @@ fn some_thing() -> u32 {
assert_eq!(res.name, "foo"); assert_eq!(res.name, "foo");
assert_snapshot!(res.expansion, @r###"bar!()"###); assert_snapshot!(res.expansion, @r###"bar!()"###);
} }
#[test]
fn macro_expand_with_dollar_crate() {
let res = check_expand_macro(
r#"
//- /lib.rs
#[macro_export]
macro_rules! bar {
() => {0};
}
macro_rules! foo {
() => {$crate::bar!()};
}
fn main() {
let res = fo<|>o!();
}
"#,
);
assert_eq!(res.name, "foo");
assert_snapshot!(res.expansion, @r###"0"###);
}
} }

View file

@ -152,7 +152,7 @@ pub(crate) fn classify_name_ref(
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
tested_by!(goto_definition_works_for_macros); tested_by!(goto_definition_works_for_macros);
if let Some(macro_def) = analyzer.resolve_macro_call(db, &macro_call) { if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) {
let kind = NameKind::Macro(macro_def); let kind = NameKind::Macro(macro_def);
return Some(NameDefinition { kind, container, visibility }); return Some(NameDefinition { kind, container, visibility });
} }