aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand/src')
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs13
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs31
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs111
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_expand/src/eager.rs32
-rw-r--r--crates/ra_hir_expand/src/lib.rs30
-rw-r--r--crates/ra_hir_expand/src/name.rs5
-rw-r--r--crates/ra_hir_expand/src/test_db.rs44
8 files changed, 181 insertions, 87 deletions
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index d19569245..f4d31526a 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -6,6 +6,8 @@
6//! changes. 6//! changes.
7 7
8use std::{ 8use std::{
9 any::type_name,
10 fmt,
9 hash::{Hash, Hasher}, 11 hash::{Hash, Hasher},
10 marker::PhantomData, 12 marker::PhantomData,
11}; 13};
@@ -14,7 +16,6 @@ use ra_arena::{Arena, Idx};
14use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; 16use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
15 17
16/// `AstId` points to an AST node in a specific file. 18/// `AstId` points to an AST node in a specific file.
17#[derive(Debug)]
18pub struct FileAstId<N: AstNode> { 19pub struct FileAstId<N: AstNode> {
19 raw: ErasedFileAstId, 20 raw: ErasedFileAstId,
20 _ty: PhantomData<fn() -> N>, 21 _ty: PhantomData<fn() -> N>,
@@ -39,11 +40,17 @@ impl<N: AstNode> Hash for FileAstId<N> {
39 } 40 }
40} 41}
41 42
43impl<N: AstNode> fmt::Debug for FileAstId<N> {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 write!(f, "FileAstId::<{}>({})", type_name::<N>(), self.raw.into_raw())
46 }
47}
48
42impl<N: AstNode> FileAstId<N> { 49impl<N: AstNode> FileAstId<N> {
43 // Can't make this a From implementation because of coherence 50 // Can't make this a From implementation because of coherence
44 pub fn upcast<M: AstNode>(self) -> FileAstId<M> 51 pub fn upcast<M: AstNode>(self) -> FileAstId<M>
45 where 52 where
46 M: From<N>, 53 N: Into<M>,
47 { 54 {
48 FileAstId { raw: self.raw, _ty: PhantomData } 55 FileAstId { raw: self.raw, _ty: PhantomData }
49 } 56 }
@@ -89,7 +96,7 @@ impl AstIdMap {
89 } 96 }
90 } 97 }
91 98
92 pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { 99 pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
93 self.arena[id.raw].clone().cast::<N>().unwrap() 100 self.arena[id.raw].clone().cast::<N>().unwrap()
94 } 101 }
95 102
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 1dc9cac66..f2d664863 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -8,8 +8,7 @@ use ra_syntax::{
8 match_ast, 8 match_ast,
9}; 9};
10 10
11use crate::db::AstDatabase; 11use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind};
12use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind};
13 12
14macro_rules! register_builtin { 13macro_rules! register_builtin {
15 ( $($trait:ident => $expand:ident),* ) => { 14 ( $($trait:ident => $expand:ident),* ) => {
@@ -156,23 +155,13 @@ fn expand_simple_derive(
156fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { 155fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
157 // FIXME: make hygiene works for builtin derive macro 156 // FIXME: make hygiene works for builtin derive macro
158 // such that $crate can be used here. 157 // such that $crate can be used here.
159
160 let m: MacroCallId = id.into();
161 let file_id = m.as_file().original_file(db);
162 let cg = db.crate_graph(); 158 let cg = db.crate_graph();
163 let krates = db.relevant_crates(file_id); 159 let krate = db.lookup_intern_macro(id).krate;
164 let krate = match krates.get(0) {
165 Some(krate) => krate,
166 None => {
167 let tt = quote! { core };
168 return tt.token_trees[0].clone();
169 }
170 };
171 160
172 // XXX 161 // XXX
173 // All crates except core itself should have a dependency on core, 162 // All crates except core itself should have a dependency on core,
174 // We detect `core` by seeing whether it doesn't have such a dependency. 163 // We detect `core` by seeing whether it doesn't have such a dependency.
175 let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") { 164 let tt = if cg[krate].dependencies.iter().any(|dep| &*dep.name == "core") {
176 quote! { core } 165 quote! { core }
177 } else { 166 } else {
178 quote! { crate } 167 quote! { crate }
@@ -264,10 +253,12 @@ fn partial_ord_expand(
264 253
265#[cfg(test)] 254#[cfg(test)]
266mod tests { 255mod tests {
267 use super::*;
268 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
269 use name::{known, Name}; 256 use name::{known, Name};
270 use ra_db::{fixture::WithFixture, SourceDatabase}; 257 use ra_db::{fixture::WithFixture, CrateId, SourceDatabase};
258
259 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
260
261 use super::*;
271 262
272 fn expand_builtin_derive(s: &str, name: Name) -> String { 263 fn expand_builtin_derive(s: &str, name: Name) -> String {
273 let def = find_builtin_derive(&name).unwrap(); 264 let def = find_builtin_derive(&name).unwrap();
@@ -291,7 +282,11 @@ mod tests {
291 282
292 let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); 283 let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
293 284
294 let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) }; 285 let loc = MacroCallLoc {
286 def,
287 krate: CrateId(0),
288 kind: MacroCallKind::Attr(attr_id, name.to_string()),
289 };
295 290
296 let id: MacroCallId = db.intern_macro(loc).into(); 291 let id: MacroCallId = db.intern_macro(loc).into();
297 let parsed = db.parse_or_expand(id.as_file()).unwrap(); 292 let parsed = db.parse_or_expand(id.as_file()).unwrap();
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 3bce8f673..9f50569dc 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -1,15 +1,14 @@
1//! Builtin macro 1//! Builtin macro
2use crate::db::AstDatabase;
3use crate::{ 2use crate::{
4 ast::{self, AstToken, HasStringValue}, 3 db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId,
5 name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize, 4 MacroDefId, MacroDefKind, TextSize,
6}; 5};
7 6
8use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId};
9use either::Either; 7use either::Either;
10use mbe::parse_to_token_tree; 8use mbe::parse_to_token_tree;
11use ra_db::{FileId, RelativePath}; 9use ra_db::FileId;
12use ra_parser::FragmentKind; 10use ra_parser::FragmentKind;
11use ra_syntax::ast::{self, AstToken, HasStringValue};
13 12
14macro_rules! register_builtin { 13macro_rules! register_builtin {
15 ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { 14 ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => {
@@ -100,6 +99,8 @@ register_builtin! {
100 EAGER: 99 EAGER:
101 (concat, Concat) => concat_expand, 100 (concat, Concat) => concat_expand,
102 (include, Include) => include_expand, 101 (include, Include) => include_expand,
102 (include_bytes, IncludeBytes) => include_bytes_expand,
103 (include_str, IncludeStr) => include_str_expand,
103 (env, Env) => env_expand, 104 (env, Env) => env_expand,
104 (option_env, OptionEnv) => option_env_expand 105 (option_env, OptionEnv) => option_env_expand
105} 106}
@@ -271,7 +272,7 @@ fn format_args_expand(
271fn unquote_str(lit: &tt::Literal) -> Option<String> { 272fn unquote_str(lit: &tt::Literal) -> Option<String> {
272 let lit = ast::make::tokens::literal(&lit.to_string()); 273 let lit = ast::make::tokens::literal(&lit.to_string());
273 let token = ast::String::cast(lit)?; 274 let token = ast::String::cast(lit)?;
274 token.value() 275 token.value().map(|it| it.into_owned())
275} 276}
276 277
277fn concat_expand( 278fn concat_expand(
@@ -293,21 +294,20 @@ fn concat_expand(
293 Ok((quote!(#text), FragmentKind::Expr)) 294 Ok((quote!(#text), FragmentKind::Expr))
294} 295}
295 296
296fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { 297fn relative_file(
298 db: &dyn AstDatabase,
299 call_id: MacroCallId,
300 path: &str,
301 allow_recursion: bool,
302) -> Option<FileId> {
297 let call_site = call_id.as_file().original_file(db); 303 let call_site = call_id.as_file().original_file(db);
298 304 let res = db.resolve_path(call_site, path)?;
299 // Handle trivial case 305 // Prevent include itself
300 if let Some(res) = db.resolve_relative_path(call_site, &RelativePath::new(&path)) { 306 if res == call_site && !allow_recursion {
301 // Prevent include itself 307 None
302 return if res == call_site { None } else { Some(res) }; 308 } else {
309 Some(res)
303 } 310 }
304
305 // Extern paths ?
306 let krate = *db.relevant_crates(call_site).get(0)?;
307 let (extern_source_id, relative_file) =
308 db.crate_graph()[krate].extern_source.extern_path(path)?;
309
310 db.resolve_extern_path(extern_source_id, &relative_file)
311} 311}
312 312
313fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { 313fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> {
@@ -326,8 +326,8 @@ fn include_expand(
326 tt: &tt::Subtree, 326 tt: &tt::Subtree,
327) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 327) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
328 let path = parse_string(tt)?; 328 let path = parse_string(tt)?;
329 let file_id = 329 let file_id = relative_file(db, arg_id.into(), &path, false)
330 relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; 330 .ok_or_else(|| mbe::ExpandError::ConversionError)?;
331 331
332 // FIXME: 332 // FIXME:
333 // Handle include as expression 333 // Handle include as expression
@@ -338,11 +338,50 @@ fn include_expand(
338 Ok((res, FragmentKind::Items)) 338 Ok((res, FragmentKind::Items))
339} 339}
340 340
341fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { 341fn include_bytes_expand(
342 let call_id: MacroCallId = arg_id.into(); 342 _db: &dyn AstDatabase,
343 let original_file = call_id.as_file().original_file(db); 343 _arg_id: EagerMacroId,
344 tt: &tt::Subtree,
345) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
346 let _path = parse_string(tt)?;
347
348 // FIXME: actually read the file here if the user asked for macro expansion
349 let res = tt::Subtree {
350 delimiter: None,
351 token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
352 text: r#"b"""#.into(),
353 id: tt::TokenId::unspecified(),
354 }))],
355 };
356 Ok((res, FragmentKind::Expr))
357}
358
359fn include_str_expand(
360 db: &dyn AstDatabase,
361 arg_id: EagerMacroId,
362 tt: &tt::Subtree,
363) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
364 let path = parse_string(tt)?;
365
366 // FIXME: we're not able to read excluded files (which is most of them because
367 // it's unusual to `include_str!` a Rust file), but we can return an empty string.
368 // Ideally, we'd be able to offer a precise expansion if the user asks for macro
369 // expansion.
370 let file_id = match relative_file(db, arg_id.into(), &path, true) {
371 Some(file_id) => file_id,
372 None => {
373 return Ok((quote!(""), FragmentKind::Expr));
374 }
375 };
376
377 let text = db.file_text(file_id);
378 let text = &*text;
344 379
345 let krate = *db.relevant_crates(original_file).get(0)?; 380 Ok((quote!(#text), FragmentKind::Expr))
381}
382
383fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
384 let krate = db.lookup_intern_eager_expansion(arg_id).krate;
346 db.crate_graph()[krate].env.get(key) 385 db.crate_graph()[krate].env.get(key)
347} 386}
348 387
@@ -401,6 +440,7 @@ mod tests {
401 440
402 let expander = find_by_name(&macro_calls[0].name().unwrap().as_name()).unwrap(); 441 let expander = find_by_name(&macro_calls[0].name().unwrap().as_name()).unwrap();
403 442
443 let krate = CrateId(0);
404 let file_id = match expander { 444 let file_id = match expander {
405 Either::Left(expander) => { 445 Either::Left(expander) => {
406 // the first one should be a macro_rules 446 // the first one should be a macro_rules
@@ -413,6 +453,7 @@ mod tests {
413 453
414 let loc = MacroCallLoc { 454 let loc = MacroCallLoc {
415 def, 455 def,
456 krate,
416 kind: MacroCallKind::FnLike(AstId::new( 457 kind: MacroCallKind::FnLike(AstId::new(
417 file_id.into(), 458 file_id.into(),
418 ast_id_map.ast_id(&macro_calls[1]), 459 ast_id_map.ast_id(&macro_calls[1]),
@@ -425,7 +466,7 @@ mod tests {
425 Either::Right(expander) => { 466 Either::Right(expander) => {
426 // the first one should be a macro_rules 467 // the first one should be a macro_rules
427 let def = MacroDefId { 468 let def = MacroDefId {
428 krate: Some(CrateId(0)), 469 krate: Some(krate),
429 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))), 470 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
430 kind: MacroDefKind::BuiltInEager(expander), 471 kind: MacroDefKind::BuiltInEager(expander),
431 local_inner: false, 472 local_inner: false,
@@ -439,6 +480,7 @@ mod tests {
439 def, 480 def,
440 fragment: FragmentKind::Expr, 481 fragment: FragmentKind::Expr,
441 subtree: Arc::new(parsed_args.clone()), 482 subtree: Arc::new(parsed_args.clone()),
483 krate,
442 file_id: file_id.into(), 484 file_id: file_id.into(),
443 } 485 }
444 }); 486 });
@@ -448,6 +490,7 @@ mod tests {
448 def, 490 def,
449 fragment, 491 fragment,
450 subtree: Arc::new(subtree), 492 subtree: Arc::new(subtree),
493 krate,
451 file_id: file_id.into(), 494 file_id: file_id.into(),
452 }; 495 };
453 496
@@ -587,4 +630,20 @@ mod tests {
587 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"# 630 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#
588 ); 631 );
589 } 632 }
633
634 #[test]
635 fn test_include_bytes_expand() {
636 let expanded = expand_builtin_macro(
637 r#"
638 #[rustc_builtin_macro]
639 macro_rules! include_bytes {
640 ($file:expr) => {{ /* compiler built-in */ }};
641 ($file:expr,) => {{ /* compiler built-in */ }};
642 }
643 include_bytes("foo");
644 "#,
645 );
646
647 assert_eq!(expanded, r#"b"""#);
648 }
590} 649}
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 99209c6e8..545cff9bd 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -28,7 +28,7 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
28 28
29pub trait AstDiagnostic { 29pub trait AstDiagnostic {
30 type AST; 30 type AST;
31 fn ast(&self, db: &impl AstDatabase) -> Self::AST; 31 fn ast(&self, db: &dyn AstDatabase) -> Self::AST;
32} 32}
33 33
34impl dyn Diagnostic { 34impl dyn Diagnostic {
diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs
index 932f47c30..302d2b3e0 100644
--- a/crates/ra_hir_expand/src/eager.rs
+++ b/crates/ra_hir_expand/src/eager.rs
@@ -25,12 +25,14 @@ use crate::{
25 EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 25 EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
26}; 26};
27 27
28use ra_db::CrateId;
28use ra_parser::FragmentKind; 29use ra_parser::FragmentKind;
29use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; 30use ra_syntax::{algo::SyntaxRewriter, SyntaxNode};
30use std::sync::Arc; 31use std::sync::Arc;
31 32
32pub fn expand_eager_macro( 33pub fn expand_eager_macro(
33 db: &dyn AstDatabase, 34 db: &dyn AstDatabase,
35 krate: CrateId,
34 macro_call: InFile<ast::MacroCall>, 36 macro_call: InFile<ast::MacroCall>,
35 def: MacroDefId, 37 def: MacroDefId,
36 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 38 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
@@ -47,6 +49,7 @@ pub fn expand_eager_macro(
47 def, 49 def,
48 fragment: FragmentKind::Expr, 50 fragment: FragmentKind::Expr,
49 subtree: Arc::new(parsed_args.clone()), 51 subtree: Arc::new(parsed_args.clone()),
52 krate,
50 file_id: macro_call.file_id, 53 file_id: macro_call.file_id,
51 } 54 }
52 }); 55 });
@@ -56,14 +59,20 @@ pub fn expand_eager_macro(
56 let result = eager_macro_recur( 59 let result = eager_macro_recur(
57 db, 60 db,
58 InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), 61 InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
62 krate,
59 resolver, 63 resolver,
60 )?; 64 )?;
61 let subtree = to_subtree(&result)?; 65 let subtree = to_subtree(&result)?;
62 66
63 if let MacroDefKind::BuiltInEager(eager) = def.kind { 67 if let MacroDefKind::BuiltInEager(eager) = def.kind {
64 let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; 68 let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?;
65 let eager = 69 let eager = EagerCallLoc {
66 EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; 70 def,
71 fragment,
72 subtree: Arc::new(subtree),
73 krate,
74 file_id: macro_call.file_id,
75 };
67 76
68 Some(db.intern_eager_expansion(eager)) 77 Some(db.intern_eager_expansion(eager))
69 } else { 78 } else {
@@ -81,11 +90,12 @@ fn lazy_expand(
81 db: &dyn AstDatabase, 90 db: &dyn AstDatabase,
82 def: &MacroDefId, 91 def: &MacroDefId,
83 macro_call: InFile<ast::MacroCall>, 92 macro_call: InFile<ast::MacroCall>,
93 krate: CrateId,
84) -> Option<InFile<SyntaxNode>> { 94) -> Option<InFile<SyntaxNode>> {
85 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); 95 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
86 96
87 let id: MacroCallId = 97 let id: MacroCallId =
88 def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); 98 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
89 99
90 db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) 100 db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node))
91} 101}
@@ -93,6 +103,7 @@ fn lazy_expand(
93fn eager_macro_recur( 103fn eager_macro_recur(
94 db: &dyn AstDatabase, 104 db: &dyn AstDatabase,
95 curr: InFile<SyntaxNode>, 105 curr: InFile<SyntaxNode>,
106 krate: CrateId,
96 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 107 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
97) -> Option<SyntaxNode> { 108) -> Option<SyntaxNode> {
98 let original = curr.value.clone(); 109 let original = curr.value.clone();
@@ -105,18 +116,23 @@ fn eager_macro_recur(
105 let def: MacroDefId = macro_resolver(child.path()?)?; 116 let def: MacroDefId = macro_resolver(child.path()?)?;
106 let insert = match def.kind { 117 let insert = match def.kind {
107 MacroDefKind::BuiltInEager(_) => { 118 MacroDefKind::BuiltInEager(_) => {
108 let id: MacroCallId = 119 let id: MacroCallId = expand_eager_macro(
109 expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)? 120 db,
110 .into(); 121 krate,
122 curr.with_value(child.clone()),
123 def,
124 macro_resolver,
125 )?
126 .into();
111 db.parse_or_expand(id.as_file())? 127 db.parse_or_expand(id.as_file())?
112 } 128 }
113 MacroDefKind::Declarative 129 MacroDefKind::Declarative
114 | MacroDefKind::BuiltIn(_) 130 | MacroDefKind::BuiltIn(_)
115 | MacroDefKind::BuiltInDerive(_) 131 | MacroDefKind::BuiltInDerive(_)
116 | MacroDefKind::CustomDerive(_) => { 132 | MacroDefKind::CustomDerive(_) => {
117 let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; 133 let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?;
118 // replace macro inside 134 // replace macro inside
119 eager_macro_recur(db, expanded, macro_resolver)? 135 eager_macro_recur(db, expanded, krate, macro_resolver)?
120 } 136 }
121 }; 137 };
122 138
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index f440c073b..1cf6c1ba9 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -88,6 +88,25 @@ impl HirFileId {
88 } 88 }
89 } 89 }
90 90
91 pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 {
92 let mut level = 0;
93 let mut curr = self;
94 while let HirFileIdRepr::MacroFile(macro_file) = curr.0 {
95 level += 1;
96 curr = match macro_file.macro_call_id {
97 MacroCallId::LazyMacro(id) => {
98 let loc = db.lookup_intern_macro(id);
99 loc.kind.file_id()
100 }
101 MacroCallId::EagerMacro(id) => {
102 let loc = db.lookup_intern_eager_expansion(id);
103 loc.file_id
104 }
105 };
106 }
107 level
108 }
109
91 /// If this is a macro call, returns the syntax node of the call. 110 /// If this is a macro call, returns the syntax node of the call.
92 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { 111 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
93 match self.0 { 112 match self.0 {
@@ -209,8 +228,13 @@ pub struct MacroDefId {
209} 228}
210 229
211impl MacroDefId { 230impl MacroDefId {
212 pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId { 231 pub fn as_lazy_macro(
213 db.intern_macro(MacroCallLoc { def: self, kind }) 232 self,
233 db: &dyn db::AstDatabase,
234 krate: CrateId,
235 kind: MacroCallKind,
236 ) -> LazyMacroId {
237 db.intern_macro(MacroCallLoc { def: self, krate, kind })
214 } 238 }
215} 239}
216 240
@@ -227,6 +251,7 @@ pub enum MacroDefKind {
227#[derive(Debug, Clone, PartialEq, Eq, Hash)] 251#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct MacroCallLoc { 252pub struct MacroCallLoc {
229 pub(crate) def: MacroDefId, 253 pub(crate) def: MacroDefId,
254 pub(crate) krate: CrateId,
230 pub(crate) kind: MacroCallKind, 255 pub(crate) kind: MacroCallKind,
231} 256}
232 257
@@ -274,6 +299,7 @@ pub struct EagerCallLoc {
274 pub(crate) def: MacroDefId, 299 pub(crate) def: MacroDefId,
275 pub(crate) fragment: FragmentKind, 300 pub(crate) fragment: FragmentKind,
276 pub(crate) subtree: Arc<tt::Subtree>, 301 pub(crate) subtree: Arc<tt::Subtree>,
302 pub(crate) krate: CrateId,
277 pub(crate) file_id: HirFileId, 303 pub(crate) file_id: HirFileId,
278} 304}
279 305
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index ea495cb11..969a2e5b8 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -117,7 +117,7 @@ impl AsName for ast::FieldKind {
117 117
118impl AsName for ra_db::Dependency { 118impl AsName for ra_db::Dependency {
119 fn as_name(&self) -> Name { 119 fn as_name(&self) -> Name {
120 Name::new_text(self.name.clone()) 120 Name::new_text(SmolStr::new(&*self.name))
121 } 121 }
122} 122}
123 123
@@ -153,6 +153,7 @@ pub mod known {
153 str, 153 str,
154 // Special names 154 // Special names
155 macro_rules, 155 macro_rules,
156 doc,
156 // Components of known path (value or mod name) 157 // Components of known path (value or mod name)
157 std, 158 std,
158 core, 159 core,
@@ -190,6 +191,8 @@ pub mod known {
190 stringify, 191 stringify,
191 concat, 192 concat,
192 include, 193 include,
194 include_bytes,
195 include_str,
193 format_args, 196 format_args,
194 format_args_nl, 197 format_args_nl,
195 env, 198 env,
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
index c1fb762de..332fa556f 100644
--- a/crates/ra_hir_expand/src/test_db.rs
+++ b/crates/ra_hir_expand/src/test_db.rs
@@ -1,36 +1,35 @@
1//! Database used for testing `hir_expand`. 1//! Database used for testing `hir_expand`.
2 2
3use std::{ 3use std::{
4 panic, 4 fmt, panic,
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; 8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate};
9use rustc_hash::FxHashSet;
9 10
10#[salsa::database( 11#[salsa::database(
11 ra_db::SourceDatabaseExtStorage, 12 ra_db::SourceDatabaseExtStorage,
12 ra_db::SourceDatabaseStorage, 13 ra_db::SourceDatabaseStorage,
13 crate::db::AstDatabaseStorage 14 crate::db::AstDatabaseStorage
14)] 15)]
15#[derive(Debug, Default)] 16#[derive(Default)]
16pub struct TestDB { 17pub struct TestDB {
17 runtime: salsa::Runtime<TestDB>, 18 storage: salsa::Storage<TestDB>,
18 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, 19 events: Mutex<Option<Vec<salsa::Event>>>,
19} 20}
20 21
21impl salsa::Database for TestDB { 22impl fmt::Debug for TestDB {
22 fn salsa_runtime(&self) -> &salsa::Runtime<Self> { 23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 &self.runtime 24 f.debug_struct("TestDB").finish()
24 }
25
26 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
27 &mut self.runtime
28 } 25 }
26}
29 27
30 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { 28impl salsa::Database for TestDB {
29 fn salsa_event(&self, event: salsa::Event) {
31 let mut events = self.events.lock().unwrap(); 30 let mut events = self.events.lock().unwrap();
32 if let Some(events) = &mut *events { 31 if let Some(events) = &mut *events {
33 events.push(event()); 32 events.push(event);
34 } 33 }
35 } 34 }
36} 35}
@@ -41,21 +40,10 @@ impl FileLoader for TestDB {
41 fn file_text(&self, file_id: FileId) -> Arc<String> { 40 fn file_text(&self, file_id: FileId) -> Arc<String> {
42 FileLoaderDelegate(self).file_text(file_id) 41 FileLoaderDelegate(self).file_text(file_id)
43 } 42 }
44 fn resolve_relative_path( 43 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
45 &self, 44 FileLoaderDelegate(self).resolve_path(anchor, path)
46 anchor: FileId,
47 relative_path: &RelativePath,
48 ) -> Option<FileId> {
49 FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
50 } 45 }
51 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 46 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
52 FileLoaderDelegate(self).relevant_crates(file_id) 47 FileLoaderDelegate(self).relevant_crates(file_id)
53 } 48 }
54 fn resolve_extern_path(
55 &self,
56 anchor: ExternSourceId,
57 relative_path: &RelativePath,
58 ) -> Option<FileId> {
59 FileLoaderDelegate(self).resolve_extern_path(anchor, relative_path)
60 }
61} 49}