diff --git a/crates/proc_macro_srv/src/tests/mod.rs b/crates/proc_macro_srv/src/tests/mod.rs index 5ca2b8a7505..d9037ee57f5 100644 --- a/crates/proc_macro_srv/src/tests/mod.rs +++ b/crates/proc_macro_srv/src/tests/mod.rs @@ -42,6 +42,19 @@ fn test_fn_like_macro() { ); } +#[test] +fn test_fn_like_macro2() { + assert_expand( + "fn_like_clone_tokens", + r#"ident, []"#, + expect![[r#" + SUBTREE $ + IDENT ident 4294967295 + PUNCH , [alone] 4294967295 + SUBTREE [] 4294967295"#]], + ); +} + #[test] fn test_attr_macro() { // Corresponds to @@ -70,6 +83,7 @@ fn list_test_macros() { fn_like_noop [FuncLike] fn_like_panic [FuncLike] fn_like_error [FuncLike] + fn_like_clone_tokens [FuncLike] attr_noop [Attr] attr_panic [Attr] attr_error [Attr] diff --git a/crates/proc_macro_test/imp/src/lib.rs b/crates/proc_macro_test/imp/src/lib.rs index 4b26d247211..980187a902f 100644 --- a/crates/proc_macro_test/imp/src/lib.rs +++ b/crates/proc_macro_test/imp/src/lib.rs @@ -1,6 +1,6 @@ //! Exports a few trivial procedural macros for testing. -use proc_macro::TokenStream; +use proc_macro::{Group, Ident, Punct, TokenStream, TokenTree}; #[proc_macro] pub fn fn_like_noop(args: TokenStream) -> TokenStream { @@ -17,6 +17,11 @@ pub fn fn_like_error(args: TokenStream) -> TokenStream { format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap() } +#[proc_macro] +pub fn fn_like_clone_tokens(args: TokenStream) -> TokenStream { + clone_stream(args) +} + #[proc_macro_attribute] pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream { item @@ -46,3 +51,24 @@ pub fn derive_panic(item: TokenStream) -> TokenStream { pub fn derive_error(item: TokenStream) -> TokenStream { format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap() } + +fn clone_stream(ts: TokenStream) -> TokenStream { + ts.into_iter().map(clone_tree).collect() +} + +fn clone_tree(t: TokenTree) -> TokenTree { + match t { + TokenTree::Group(orig) => { + let mut new = Group::new(orig.delimiter(), clone_stream(orig.stream())); + new.set_span(orig.span()); + TokenTree::Group(new) + } + TokenTree::Ident(orig) => TokenTree::Ident(Ident::new(&orig.to_string(), orig.span())), + TokenTree::Punct(orig) => { + let mut new = Punct::new(orig.as_char(), orig.spacing()); + new.set_span(orig.span()); + TokenTree::Punct(new) + } + TokenTree::Literal(_orig) => unimplemented!(), + } +}