mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 15:14:32 +00:00
Merge #4843
4843: Don't guess macro expansion crate r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
32157d48f4
17 changed files with 116 additions and 77 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1013,6 +1013,7 @@ dependencies = [
|
||||||
"ra_prof",
|
"ra_prof",
|
||||||
"ra_syntax",
|
"ra_syntax",
|
||||||
"ra_tt",
|
"ra_tt",
|
||||||
|
"rustc-hash",
|
||||||
"test_utils",
|
"test_utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,10 @@ use std::{
|
||||||
|
|
||||||
use ra_cfg::CfgOptions;
|
use ra_cfg::CfgOptions;
|
||||||
use ra_syntax::SmolStr;
|
use ra_syntax::SmolStr;
|
||||||
use rustc_hash::FxHashMap;
|
use ra_tt::TokenExpander;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::{RelativePath, RelativePathBuf};
|
use crate::{RelativePath, RelativePathBuf};
|
||||||
use fmt::Display;
|
|
||||||
use ra_tt::TokenExpander;
|
|
||||||
|
|
||||||
/// `FileId` is an integer which uniquely identifies a file. File paths are
|
/// `FileId` is an integer which uniquely identifies a file. File paths are
|
||||||
/// messy and system-dependent, so most of the code should work directly with
|
/// messy and system-dependent, so most of the code should work directly with
|
||||||
|
@ -111,7 +109,7 @@ impl CrateName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for CrateName {
|
impl fmt::Display for CrateName {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::{panic, sync::Arc};
|
||||||
|
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize};
|
use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
cancellation::Canceled,
|
cancellation::Canceled,
|
||||||
|
@ -95,7 +96,7 @@ pub trait FileLoader {
|
||||||
/// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we
|
/// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we
|
||||||
/// get by with a `&str` for the time being.
|
/// get by with a `&str` for the time being.
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
|
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>;
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Database which stores all significant input facts: source code and project
|
/// Database which stores all significant input facts: source code and project
|
||||||
|
@ -133,16 +134,21 @@ pub trait SourceDatabaseExt: SourceDatabase {
|
||||||
#[salsa::input]
|
#[salsa::input]
|
||||||
fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
|
fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
|
||||||
|
|
||||||
fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
|
fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_root_crates(
|
fn source_root_crates(
|
||||||
db: &(impl SourceDatabaseExt + SourceDatabase),
|
db: &(impl SourceDatabaseExt + SourceDatabase),
|
||||||
id: SourceRootId,
|
id: SourceRootId,
|
||||||
) -> Arc<Vec<CrateId>> {
|
) -> Arc<FxHashSet<CrateId>> {
|
||||||
let root = db.source_root(id);
|
|
||||||
let graph = db.crate_graph();
|
let graph = db.crate_graph();
|
||||||
let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
|
let res = graph
|
||||||
|
.iter()
|
||||||
|
.filter(|&krate| {
|
||||||
|
let root_file = graph[krate].root_file_id;
|
||||||
|
db.file_source_root(root_file) == id
|
||||||
|
})
|
||||||
|
.collect::<FxHashSet<_>>();
|
||||||
Arc::new(res)
|
Arc::new(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +162,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
||||||
// FIXME: this *somehow* should be platform agnostic...
|
// FIXME: this *somehow* should be platform agnostic...
|
||||||
if std::path::Path::new(path).is_absolute() {
|
if std::path::Path::new(path).is_absolute() {
|
||||||
let krate = *self.relevant_crates(anchor).get(0)?;
|
let krate = *self.relevant_crates(anchor).iter().next()?;
|
||||||
let (extern_source_id, relative_file) =
|
let (extern_source_id, relative_file) =
|
||||||
self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?;
|
self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?;
|
||||||
|
|
||||||
|
@ -175,7 +181,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
let source_root = self.0.file_source_root(file_id);
|
let source_root = self.0.file_source_root(file_id);
|
||||||
self.0.source_root_crates(source_root)
|
self.0.source_root_crates(source_root)
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,8 +122,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||||
let macro_call =
|
let macro_call =
|
||||||
self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
|
self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
|
||||||
let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
|
let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
|
||||||
|
let krate = sa.resolver.krate()?;
|
||||||
let macro_call_id = macro_call
|
let macro_call_id = macro_call
|
||||||
.as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?;
|
.as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?;
|
||||||
hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map)
|
hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,8 @@ impl SourceAnalyzer {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
macro_call: InFile<&ast::MacroCall>,
|
macro_call: InFile<&ast::MacroCall>,
|
||||||
) -> Option<HirFileId> {
|
) -> Option<HirFileId> {
|
||||||
let macro_call_id = macro_call.as_call_id(db.upcast(), |path| {
|
let krate = self.resolver.krate()?;
|
||||||
|
let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
|
||||||
self.resolver.resolve_path_as_macro(db.upcast(), &path)
|
self.resolver.resolve_path_as_macro(db.upcast(), &path)
|
||||||
})?;
|
})?;
|
||||||
Some(macro_call_id.as_file())
|
Some(macro_call_id.as_file())
|
||||||
|
|
|
@ -97,7 +97,7 @@ impl Expander {
|
||||||
|
|
||||||
let macro_call = InFile::new(self.current_file_id, ¯o_call);
|
let macro_call = InFile::new(self.current_file_id, ¯o_call);
|
||||||
|
|
||||||
if let Some(call_id) = macro_call.as_call_id(db, |path| {
|
if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| {
|
||||||
if let Some(local_scope) = local_scope {
|
if let Some(local_scope) = local_scope {
|
||||||
if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
|
if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
|
||||||
return Some(def);
|
return Some(def);
|
||||||
|
|
|
@ -417,6 +417,7 @@ pub trait AsMacroCall {
|
||||||
fn as_call_id(
|
fn as_call_id(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn db::DefDatabase,
|
||||||
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Option<MacroCallId>;
|
) -> Option<MacroCallId>;
|
||||||
}
|
}
|
||||||
|
@ -425,13 +426,14 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
|
||||||
fn as_call_id(
|
fn as_call_id(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn db::DefDatabase,
|
||||||
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Option<MacroCallId> {
|
) -> Option<MacroCallId> {
|
||||||
let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
|
let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
|
||||||
let h = Hygiene::new(db.upcast(), self.file_id);
|
let h = Hygiene::new(db.upcast(), self.file_id);
|
||||||
let path = path::ModPath::from_src(self.value.path()?, &h)?;
|
let path = path::ModPath::from_src(self.value.path()?, &h)?;
|
||||||
|
|
||||||
AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver)
|
AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +454,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
|
||||||
fn as_call_id(
|
fn as_call_id(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn db::DefDatabase,
|
||||||
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Option<MacroCallId> {
|
) -> Option<MacroCallId> {
|
||||||
let def: MacroDefId = resolver(self.path.clone())?;
|
let def: MacroDefId = resolver(self.path.clone())?;
|
||||||
|
@ -461,13 +464,13 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
|
||||||
let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
|
let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
expand_eager_macro(db.upcast(), macro_call, def, &|path: ast::Path| {
|
expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| {
|
||||||
resolver(path::ModPath::from_src(path, &hygiene)?)
|
resolver(path::ModPath::from_src(path, &hygiene)?)
|
||||||
})?
|
})?
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Some(def.as_lazy_macro(db.upcast(), MacroCallKind::FnLike(self.ast_id)).into())
|
Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,12 +479,14 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> {
|
||||||
fn as_call_id(
|
fn as_call_id(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn db::DefDatabase,
|
||||||
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Option<MacroCallId> {
|
) -> Option<MacroCallId> {
|
||||||
let def = resolver(self.path.clone())?;
|
let def = resolver(self.path.clone())?;
|
||||||
Some(
|
Some(
|
||||||
def.as_lazy_macro(
|
def.as_lazy_macro(
|
||||||
db.upcast(),
|
db.upcast(),
|
||||||
|
krate,
|
||||||
MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()),
|
MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
|
|
|
@ -571,16 +571,18 @@ impl DefCollector<'_> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| {
|
if let Some(call_id) =
|
||||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
|
||||||
self.db,
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||||
ResolveMode::Other,
|
self.db,
|
||||||
directive.module_id,
|
ResolveMode::Other,
|
||||||
&path,
|
directive.module_id,
|
||||||
BuiltinShadowMode::Module,
|
&path,
|
||||||
);
|
BuiltinShadowMode::Module,
|
||||||
resolved_res.resolved_def.take_macros()
|
);
|
||||||
}) {
|
resolved_res.resolved_def.take_macros()
|
||||||
|
})
|
||||||
|
{
|
||||||
resolved.push((directive.module_id, call_id, directive.depth));
|
resolved.push((directive.module_id, call_id, directive.depth));
|
||||||
res = ReachedFixedPoint::No;
|
res = ReachedFixedPoint::No;
|
||||||
return false;
|
return false;
|
||||||
|
@ -589,9 +591,10 @@ impl DefCollector<'_> {
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
attribute_macros.retain(|directive| {
|
attribute_macros.retain(|directive| {
|
||||||
if let Some(call_id) = directive
|
if let Some(call_id) =
|
||||||
.ast_id
|
directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
|
||||||
.as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path))
|
self.resolve_attribute_macro(&directive, &path)
|
||||||
|
})
|
||||||
{
|
{
|
||||||
resolved.push((directive.module_id, call_id, 0));
|
resolved.push((directive.module_id, call_id, 0));
|
||||||
res = ReachedFixedPoint::No;
|
res = ReachedFixedPoint::No;
|
||||||
|
@ -957,11 +960,13 @@ impl ModCollector<'_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 2: try to resolve in legacy scope and expand macro_rules
|
// Case 2: try to resolve in legacy scope and expand macro_rules
|
||||||
if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| {
|
if let Some(macro_call_id) =
|
||||||
path.as_ident().and_then(|name| {
|
ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
|
||||||
self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
|
path.as_ident().and_then(|name| {
|
||||||
|
self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}) {
|
{
|
||||||
self.def_collector.unexpanded_macros.push(MacroDirective {
|
self.def_collector.unexpanded_macros.push(MacroDirective {
|
||||||
module_id: self.module_id,
|
module_id: self.module_id,
|
||||||
ast_id,
|
ast_id,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::{
|
||||||
|
|
||||||
use hir_expand::db::AstDatabase;
|
use hir_expand::db::AstDatabase;
|
||||||
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
|
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::db::DefDatabase;
|
use crate::db::DefDatabase;
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ impl FileLoader for TestDB {
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(anchor, path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ doctest = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
either = "1.5.3"
|
either = "1.5.3"
|
||||||
|
rustc-hash = "1.0.0"
|
||||||
|
|
||||||
ra_arena = { path = "../ra_arena" }
|
ra_arena = { path = "../ra_arena" }
|
||||||
ra_db = { path = "../ra_db" }
|
ra_db = { path = "../ra_db" }
|
||||||
|
|
|
@ -8,8 +8,7 @@ use ra_syntax::{
|
||||||
match_ast,
|
match_ast,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::db::AstDatabase;
|
use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind};
|
||||||
use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind};
|
|
||||||
|
|
||||||
macro_rules! register_builtin {
|
macro_rules! register_builtin {
|
||||||
( $($trait:ident => $expand:ident),* ) => {
|
( $($trait:ident => $expand:ident),* ) => {
|
||||||
|
@ -156,23 +155,13 @@ fn expand_simple_derive(
|
||||||
fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
|
fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
|
||||||
// FIXME: make hygiene works for builtin derive macro
|
// FIXME: make hygiene works for builtin derive macro
|
||||||
// such that $crate can be used here.
|
// such that $crate can be used here.
|
||||||
|
|
||||||
let m: MacroCallId = id.into();
|
|
||||||
let file_id = m.as_file().original_file(db);
|
|
||||||
let cg = db.crate_graph();
|
let cg = db.crate_graph();
|
||||||
let krates = db.relevant_crates(file_id);
|
let krate = db.lookup_intern_macro(id).krate;
|
||||||
let krate = match krates.get(0) {
|
|
||||||
Some(krate) => krate,
|
|
||||||
None => {
|
|
||||||
let tt = quote! { core };
|
|
||||||
return tt.token_trees[0].clone();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// XXX
|
// XXX
|
||||||
// All crates except core itself should have a dependency on core,
|
// All crates except core itself should have a dependency on core,
|
||||||
// We detect `core` by seeing whether it doesn't have such a dependency.
|
// We detect `core` by seeing whether it doesn't have such a dependency.
|
||||||
let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") {
|
let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") {
|
||||||
quote! { core }
|
quote! { core }
|
||||||
} else {
|
} else {
|
||||||
quote! { crate }
|
quote! { crate }
|
||||||
|
@ -264,10 +253,12 @@ fn partial_ord_expand(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
|
|
||||||
use name::{known, Name};
|
use name::{known, Name};
|
||||||
use ra_db::{fixture::WithFixture, SourceDatabase};
|
use ra_db::{fixture::WithFixture, CrateId, SourceDatabase};
|
||||||
|
|
||||||
|
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
fn expand_builtin_derive(s: &str, name: Name) -> String {
|
fn expand_builtin_derive(s: &str, name: Name) -> String {
|
||||||
let def = find_builtin_derive(&name).unwrap();
|
let def = find_builtin_derive(&name).unwrap();
|
||||||
|
@ -291,7 +282,11 @@ mod tests {
|
||||||
|
|
||||||
let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
|
let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
|
||||||
|
|
||||||
let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) };
|
let loc = MacroCallLoc {
|
||||||
|
def,
|
||||||
|
krate: CrateId(0),
|
||||||
|
kind: MacroCallKind::Attr(attr_id, name.to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
let id: MacroCallId = db.intern_macro(loc).into();
|
let id: MacroCallId = db.intern_macro(loc).into();
|
||||||
let parsed = db.parse_or_expand(id.as_file()).unwrap();
|
let parsed = db.parse_or_expand(id.as_file()).unwrap();
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
//! Builtin macro
|
//! Builtin macro
|
||||||
use crate::db::AstDatabase;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, AstToken, HasStringValue},
|
db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId,
|
||||||
name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize,
|
MacroDefId, MacroDefKind, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId};
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use mbe::parse_to_token_tree;
|
use mbe::parse_to_token_tree;
|
||||||
use ra_db::FileId;
|
use ra_db::FileId;
|
||||||
use ra_parser::FragmentKind;
|
use ra_parser::FragmentKind;
|
||||||
|
use ra_syntax::ast::{self, AstToken, HasStringValue};
|
||||||
|
|
||||||
macro_rules! register_builtin {
|
macro_rules! register_builtin {
|
||||||
( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => {
|
( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => {
|
||||||
|
@ -333,10 +332,7 @@ fn include_expand(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
|
fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
|
||||||
let call_id: MacroCallId = arg_id.into();
|
let krate = db.lookup_intern_eager_expansion(arg_id).krate;
|
||||||
let original_file = call_id.as_file().original_file(db);
|
|
||||||
|
|
||||||
let krate = *db.relevant_crates(original_file).get(0)?;
|
|
||||||
db.crate_graph()[krate].env.get(key)
|
db.crate_graph()[krate].env.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,6 +391,7 @@ mod tests {
|
||||||
|
|
||||||
let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap();
|
let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap();
|
||||||
|
|
||||||
|
let krate = CrateId(0);
|
||||||
let file_id = match expander {
|
let file_id = match expander {
|
||||||
Either::Left(expander) => {
|
Either::Left(expander) => {
|
||||||
// the first one should be a macro_rules
|
// the first one should be a macro_rules
|
||||||
|
@ -407,6 +404,7 @@ mod tests {
|
||||||
|
|
||||||
let loc = MacroCallLoc {
|
let loc = MacroCallLoc {
|
||||||
def,
|
def,
|
||||||
|
krate,
|
||||||
kind: MacroCallKind::FnLike(AstId::new(
|
kind: MacroCallKind::FnLike(AstId::new(
|
||||||
file_id.into(),
|
file_id.into(),
|
||||||
ast_id_map.ast_id(¯o_calls[1]),
|
ast_id_map.ast_id(¯o_calls[1]),
|
||||||
|
@ -419,7 +417,7 @@ mod tests {
|
||||||
Either::Right(expander) => {
|
Either::Right(expander) => {
|
||||||
// the first one should be a macro_rules
|
// the first one should be a macro_rules
|
||||||
let def = MacroDefId {
|
let def = MacroDefId {
|
||||||
krate: Some(CrateId(0)),
|
krate: Some(krate),
|
||||||
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))),
|
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))),
|
||||||
kind: MacroDefKind::BuiltInEager(expander),
|
kind: MacroDefKind::BuiltInEager(expander),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
|
@ -433,6 +431,7 @@ mod tests {
|
||||||
def,
|
def,
|
||||||
fragment: FragmentKind::Expr,
|
fragment: FragmentKind::Expr,
|
||||||
subtree: Arc::new(parsed_args.clone()),
|
subtree: Arc::new(parsed_args.clone()),
|
||||||
|
krate,
|
||||||
file_id: file_id.into(),
|
file_id: file_id.into(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -442,6 +441,7 @@ mod tests {
|
||||||
def,
|
def,
|
||||||
fragment,
|
fragment,
|
||||||
subtree: Arc::new(subtree),
|
subtree: Arc::new(subtree),
|
||||||
|
krate,
|
||||||
file_id: file_id.into(),
|
file_id: file_id.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,14 @@ use crate::{
|
||||||
EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use ra_db::CrateId;
|
||||||
use ra_parser::FragmentKind;
|
use ra_parser::FragmentKind;
|
||||||
use ra_syntax::{algo::SyntaxRewriter, SyntaxNode};
|
use ra_syntax::{algo::SyntaxRewriter, SyntaxNode};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub fn expand_eager_macro(
|
pub fn expand_eager_macro(
|
||||||
db: &dyn AstDatabase,
|
db: &dyn AstDatabase,
|
||||||
|
krate: CrateId,
|
||||||
macro_call: InFile<ast::MacroCall>,
|
macro_call: InFile<ast::MacroCall>,
|
||||||
def: MacroDefId,
|
def: MacroDefId,
|
||||||
resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
|
resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
|
||||||
|
@ -47,6 +49,7 @@ pub fn expand_eager_macro(
|
||||||
def,
|
def,
|
||||||
fragment: FragmentKind::Expr,
|
fragment: FragmentKind::Expr,
|
||||||
subtree: Arc::new(parsed_args.clone()),
|
subtree: Arc::new(parsed_args.clone()),
|
||||||
|
krate,
|
||||||
file_id: macro_call.file_id,
|
file_id: macro_call.file_id,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -56,14 +59,20 @@ pub fn expand_eager_macro(
|
||||||
let result = eager_macro_recur(
|
let result = eager_macro_recur(
|
||||||
db,
|
db,
|
||||||
InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
|
InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
|
||||||
|
krate,
|
||||||
resolver,
|
resolver,
|
||||||
)?;
|
)?;
|
||||||
let subtree = to_subtree(&result)?;
|
let subtree = to_subtree(&result)?;
|
||||||
|
|
||||||
if let MacroDefKind::BuiltInEager(eager) = def.kind {
|
if let MacroDefKind::BuiltInEager(eager) = def.kind {
|
||||||
let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?;
|
let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?;
|
||||||
let eager =
|
let eager = EagerCallLoc {
|
||||||
EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id };
|
def,
|
||||||
|
fragment,
|
||||||
|
subtree: Arc::new(subtree),
|
||||||
|
krate,
|
||||||
|
file_id: macro_call.file_id,
|
||||||
|
};
|
||||||
|
|
||||||
Some(db.intern_eager_expansion(eager))
|
Some(db.intern_eager_expansion(eager))
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,11 +90,12 @@ fn lazy_expand(
|
||||||
db: &dyn AstDatabase,
|
db: &dyn AstDatabase,
|
||||||
def: &MacroDefId,
|
def: &MacroDefId,
|
||||||
macro_call: InFile<ast::MacroCall>,
|
macro_call: InFile<ast::MacroCall>,
|
||||||
|
krate: CrateId,
|
||||||
) -> Option<InFile<SyntaxNode>> {
|
) -> Option<InFile<SyntaxNode>> {
|
||||||
let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value);
|
let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value);
|
||||||
|
|
||||||
let id: MacroCallId =
|
let id: MacroCallId =
|
||||||
def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
|
def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
|
||||||
|
|
||||||
db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node))
|
db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node))
|
||||||
}
|
}
|
||||||
|
@ -93,6 +103,7 @@ fn lazy_expand(
|
||||||
fn eager_macro_recur(
|
fn eager_macro_recur(
|
||||||
db: &dyn AstDatabase,
|
db: &dyn AstDatabase,
|
||||||
curr: InFile<SyntaxNode>,
|
curr: InFile<SyntaxNode>,
|
||||||
|
krate: CrateId,
|
||||||
macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
|
macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
|
||||||
) -> Option<SyntaxNode> {
|
) -> Option<SyntaxNode> {
|
||||||
let original = curr.value.clone();
|
let original = curr.value.clone();
|
||||||
|
@ -105,18 +116,23 @@ fn eager_macro_recur(
|
||||||
let def: MacroDefId = macro_resolver(child.path()?)?;
|
let def: MacroDefId = macro_resolver(child.path()?)?;
|
||||||
let insert = match def.kind {
|
let insert = match def.kind {
|
||||||
MacroDefKind::BuiltInEager(_) => {
|
MacroDefKind::BuiltInEager(_) => {
|
||||||
let id: MacroCallId =
|
let id: MacroCallId = expand_eager_macro(
|
||||||
expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)?
|
db,
|
||||||
.into();
|
krate,
|
||||||
|
curr.with_value(child.clone()),
|
||||||
|
def,
|
||||||
|
macro_resolver,
|
||||||
|
)?
|
||||||
|
.into();
|
||||||
db.parse_or_expand(id.as_file())?
|
db.parse_or_expand(id.as_file())?
|
||||||
}
|
}
|
||||||
MacroDefKind::Declarative
|
MacroDefKind::Declarative
|
||||||
| MacroDefKind::BuiltIn(_)
|
| MacroDefKind::BuiltIn(_)
|
||||||
| MacroDefKind::BuiltInDerive(_)
|
| MacroDefKind::BuiltInDerive(_)
|
||||||
| MacroDefKind::CustomDerive(_) => {
|
| MacroDefKind::CustomDerive(_) => {
|
||||||
let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?;
|
let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?;
|
||||||
// replace macro inside
|
// replace macro inside
|
||||||
eager_macro_recur(db, expanded, macro_resolver)?
|
eager_macro_recur(db, expanded, krate, macro_resolver)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -209,8 +209,13 @@ pub struct MacroDefId {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacroDefId {
|
impl MacroDefId {
|
||||||
pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId {
|
pub fn as_lazy_macro(
|
||||||
db.intern_macro(MacroCallLoc { def: self, kind })
|
self,
|
||||||
|
db: &dyn db::AstDatabase,
|
||||||
|
krate: CrateId,
|
||||||
|
kind: MacroCallKind,
|
||||||
|
) -> LazyMacroId {
|
||||||
|
db.intern_macro(MacroCallLoc { def: self, krate, kind })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +232,7 @@ pub enum MacroDefKind {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct MacroCallLoc {
|
pub struct MacroCallLoc {
|
||||||
pub(crate) def: MacroDefId,
|
pub(crate) def: MacroDefId,
|
||||||
|
pub(crate) krate: CrateId,
|
||||||
pub(crate) kind: MacroCallKind,
|
pub(crate) kind: MacroCallKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +280,7 @@ pub struct EagerCallLoc {
|
||||||
pub(crate) def: MacroDefId,
|
pub(crate) def: MacroDefId,
|
||||||
pub(crate) fragment: FragmentKind,
|
pub(crate) fragment: FragmentKind,
|
||||||
pub(crate) subtree: Arc<tt::Subtree>,
|
pub(crate) subtree: Arc<tt::Subtree>,
|
||||||
|
pub(crate) krate: CrateId,
|
||||||
pub(crate) file_id: HirFileId,
|
pub(crate) file_id: HirFileId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate};
|
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
#[salsa::database(
|
#[salsa::database(
|
||||||
ra_db::SourceDatabaseExtStorage,
|
ra_db::SourceDatabaseExtStorage,
|
||||||
|
@ -44,7 +45,7 @@ impl FileLoader for TestDB {
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(anchor, path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::{
|
||||||
use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId};
|
use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId};
|
||||||
use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
|
use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
|
||||||
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
|
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
|
|
||||||
use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator};
|
use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator};
|
||||||
|
@ -73,7 +74,7 @@ impl FileLoader for TestDB {
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(anchor, path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use ra_db::{
|
||||||
Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
|
Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
|
||||||
SourceRootId, Upcast,
|
SourceRootId, Upcast,
|
||||||
};
|
};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
|
use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ impl FileLoader for RootDatabase {
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(anchor, path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue