aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand/src/builtin_macro.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand/src/builtin_macro.rs')
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs73
1 files changed, 69 insertions, 4 deletions
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index b50eb347c..626f9efd0 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -99,6 +99,8 @@ register_builtin! {
99 EAGER: 99 EAGER:
100 (concat, Concat) => concat_expand, 100 (concat, Concat) => concat_expand,
101 (include, Include) => include_expand, 101 (include, Include) => include_expand,
102 (include_bytes, IncludeBytes) => include_bytes_expand,
103 (include_str, IncludeStr) => include_str_expand,
102 (env, Env) => env_expand, 104 (env, Env) => env_expand,
103 (option_env, OptionEnv) => option_env_expand 105 (option_env, OptionEnv) => option_env_expand
104} 106}
@@ -292,11 +294,16 @@ fn concat_expand(
292 Ok((quote!(#text), FragmentKind::Expr)) 294 Ok((quote!(#text), FragmentKind::Expr))
293} 295}
294 296
295fn 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> {
296 let call_site = call_id.as_file().original_file(db); 303 let call_site = call_id.as_file().original_file(db);
297 let res = db.resolve_path(call_site, path)?; 304 let res = db.resolve_path(call_site, path)?;
298 // Prevent include itself 305 // Prevent include itself
299 if res == call_site { 306 if res == call_site && !allow_recursion {
300 None 307 None
301 } else { 308 } else {
302 Some(res) 309 Some(res)
@@ -319,8 +326,8 @@ fn include_expand(
319 tt: &tt::Subtree, 326 tt: &tt::Subtree,
320) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 327) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
321 let path = parse_string(tt)?; 328 let path = parse_string(tt)?;
322 let file_id = 329 let file_id = relative_file(db, arg_id.into(), &path, false)
323 relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; 330 .ok_or_else(|| mbe::ExpandError::ConversionError)?;
324 331
325 // FIXME: 332 // FIXME:
326 // Handle include as expression 333 // Handle include as expression
@@ -331,6 +338,48 @@ fn include_expand(
331 Ok((res, FragmentKind::Items)) 338 Ok((res, FragmentKind::Items))
332} 339}
333 340
341fn include_bytes_expand(
342 _db: &dyn AstDatabase,
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;
379
380 Ok((quote!(#text), FragmentKind::Expr))
381}
382
334fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { 383fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
335 let krate = db.lookup_intern_eager_expansion(arg_id).krate; 384 let krate = db.lookup_intern_eager_expansion(arg_id).krate;
336 db.crate_graph()[krate].env.get(key) 385 db.crate_graph()[krate].env.get(key)
@@ -581,4 +630,20 @@ mod tests {
581 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),])"#
582 ); 631 );
583 } 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 }
584} 649}