diff options
Diffstat (limited to 'crates/ra_hir_expand/src')
-rw-r--r-- | crates/ra_hir_expand/src/ast_id_map.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/builtin_derive.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 111 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/eager.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/name.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/test_db.rs | 44 |
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 | ||
8 | use std::{ | 8 | use 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}; | |||
14 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; | 16 | use 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)] | ||
18 | pub struct FileAstId<N: AstNode> { | 19 | pub 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 | ||
43 | impl<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 | |||
42 | impl<N: AstNode> FileAstId<N> { | 49 | impl<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 | ||
11 | use crate::db::AstDatabase; | 11 | use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind}; |
12 | use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
15 | ( $($trait:ident => $expand:ident),* ) => { | 14 | ( $($trait:ident => $expand:ident),* ) => { |
@@ -156,23 +155,13 @@ fn expand_simple_derive( | |||
156 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { | 155 | fn 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)] |
266 | mod tests { | 255 | mod 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 |
2 | use crate::db::AstDatabase; | ||
3 | use crate::{ | 2 | use 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 | ||
8 | use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; | ||
9 | use either::Either; | 7 | use either::Either; |
10 | use mbe::parse_to_token_tree; | 8 | use mbe::parse_to_token_tree; |
11 | use ra_db::{FileId, RelativePath}; | 9 | use ra_db::FileId; |
12 | use ra_parser::FragmentKind; | 10 | use ra_parser::FragmentKind; |
11 | use ra_syntax::ast::{self, AstToken, HasStringValue}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_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( | |||
271 | fn unquote_str(lit: &tt::Literal) -> Option<String> { | 272 | fn 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 | ||
277 | fn concat_expand( | 278 | fn 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 | ||
296 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { | 297 | fn 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 | ||
313 | fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { | 313 | fn 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 | ||
341 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | 341 | fn 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 | |||
359 | fn 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 | |||
383 | fn 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(¯o_calls[0].name().unwrap().as_name()).unwrap(); | 441 | let expander = find_by_name(¯o_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(¯o_calls[1]), | 459 | ast_id_map.ast_id(¯o_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(¯o_calls[0]))), | 470 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_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 | ||
29 | pub trait AstDiagnostic { | 29 | pub 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 | ||
34 | impl dyn Diagnostic { | 34 | impl 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 | ||
28 | use ra_db::CrateId; | ||
28 | use ra_parser::FragmentKind; | 29 | use ra_parser::FragmentKind; |
29 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; | 30 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; |
30 | use std::sync::Arc; | 31 | use std::sync::Arc; |
31 | 32 | ||
32 | pub fn expand_eager_macro( | 33 | pub 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(¯o_call.value); | 95 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_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( | |||
93 | fn eager_macro_recur( | 103 | fn 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 | ||
211 | impl MacroDefId { | 230 | impl 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)] |
228 | pub struct MacroCallLoc { | 252 | pub 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 | ||
118 | impl AsName for ra_db::Dependency { | 118 | impl 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 | ||
3 | use std::{ | 3 | use std::{ |
4 | panic, | 4 | fmt, panic, |
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | 8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; |
9 | use 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)] |
16 | pub struct TestDB { | 17 | pub 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 | ||
21 | impl salsa::Database for TestDB { | 22 | impl 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>) { | 28 | impl 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 | } |