Merge commit '457b966b17' into sync-from-ra

This commit is contained in:
Laurențiu Nicola 2023-12-11 11:16:01 +02:00
parent 5285df4f6c
commit f532576ac5
263 changed files with 9788 additions and 6258 deletions

View file

@ -11,7 +11,7 @@ use libloading::Library;
use memmap2::Mmap;
use object::Object;
use paths::AbsPath;
use proc_macro_api::{read_dylib_info, ProcMacroKind};
use proc_macro_api::{msg::TokenId, read_dylib_info, ProcMacroKind};
const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
@ -152,9 +152,15 @@ impl Expander {
macro_name: &str,
macro_body: &crate::tt::Subtree,
attributes: Option<&crate::tt::Subtree>,
def_site: TokenId,
call_site: TokenId,
mixed_site: TokenId,
) -> Result<crate::tt::Subtree, String> {
let result = self.inner.proc_macros.expand(macro_name, macro_body, attributes);
result.map_err(|e| e.as_str().unwrap_or_else(|| "<unknown error>".to_string()))
let result = self
.inner
.proc_macros
.expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site);
result.map_err(|e| e.into_string().unwrap_or_default())
}
pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {

View file

@ -10,9 +10,9 @@
//! * By **copying** the whole rustc `lib_proc_macro` code, we are able to build this with `stable`
//! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)…
#![cfg(feature = "sysroot-abi")]
#![cfg(any(feature = "sysroot-abi", rust_analyzer))]
#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)]
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(unreachable_pub, internal_features)]
extern crate proc_macro;
@ -32,11 +32,23 @@ use std::{
};
use proc_macro_api::{
msg::{self, CURRENT_API_VERSION},
msg::{self, ExpnGlobals, TokenId, CURRENT_API_VERSION},
ProcMacroKind,
};
use ::tt::token_id as tt;
mod tt {
pub use proc_macro_api::msg::TokenId;
pub use ::tt::*;
pub type Subtree = ::tt::Subtree<TokenId>;
pub type TokenTree = ::tt::TokenTree<TokenId>;
pub type Delimiter = ::tt::Delimiter<TokenId>;
pub type Leaf = ::tt::Leaf<TokenId>;
pub type Literal = ::tt::Literal<TokenId>;
pub type Punct = ::tt::Punct<TokenId>;
pub type Ident = ::tt::Ident<TokenId>;
}
// see `build.rs`
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
@ -70,16 +82,28 @@ impl ProcMacroSrv {
None => None,
};
let macro_body = task.macro_body.to_subtree(CURRENT_API_VERSION);
let attributes = task.attributes.map(|it| it.to_subtree(CURRENT_API_VERSION));
let ExpnGlobals { def_site, call_site, mixed_site, .. } = task.has_global_spans;
let def_site = TokenId(def_site as u32);
let call_site = TokenId(call_site as u32);
let mixed_site = TokenId(mixed_site as u32);
let macro_body = task.macro_body.to_subtree_unresolved(CURRENT_API_VERSION);
let attributes = task.attributes.map(|it| it.to_subtree_unresolved(CURRENT_API_VERSION));
let result = thread::scope(|s| {
let thread = thread::Builder::new()
.stack_size(EXPANDER_STACK_SIZE)
.name(task.macro_name.clone())
.spawn_scoped(s, || {
expander
.expand(&task.macro_name, &macro_body, attributes.as_ref())
.map(|it| msg::FlatTree::new(&it, CURRENT_API_VERSION))
.expand(
&task.macro_name,
&macro_body,
attributes.as_ref(),
def_site,
call_site,
mixed_site,
)
.map(|it| msg::FlatTree::new_raw(&it, CURRENT_API_VERSION))
});
let res = match thread {
Ok(handle) => handle.join(),
@ -136,8 +160,8 @@ pub struct PanicMessage {
}
impl PanicMessage {
pub fn as_str(&self) -> Option<String> {
self.message.clone()
pub fn into_string(self) -> Option<String> {
self.message
}
}

View file

@ -1,16 +1,17 @@
//! Proc macro ABI
use libloading::Library;
use proc_macro_api::{ProcMacroKind, RustCInfo};
use proc_macro::bridge;
use proc_macro_api::{msg::TokenId, ProcMacroKind, RustCInfo};
use crate::{dylib::LoadProcMacroDylibError, server::SYMBOL_INTERNER, tt};
pub(crate) struct ProcMacros {
exported_macros: Vec<proc_macro::bridge::client::ProcMacro>,
exported_macros: Vec<bridge::client::ProcMacro>,
}
impl From<proc_macro::bridge::PanicMessage> for crate::PanicMessage {
fn from(p: proc_macro::bridge::PanicMessage) -> Self {
impl From<bridge::PanicMessage> for crate::PanicMessage {
fn from(p: bridge::PanicMessage) -> Self {
Self { message: p.as_str().map(|s| s.to_string()) }
}
}
@ -31,9 +32,8 @@ impl ProcMacros {
info: RustCInfo,
) -> Result<ProcMacros, LoadProcMacroDylibError> {
if info.version_string == crate::RUSTC_VERSION_STRING {
let macros = unsafe {
lib.get::<&&[proc_macro::bridge::client::ProcMacro]>(symbol_name.as_bytes())
}?;
let macros =
unsafe { lib.get::<&&[bridge::client::ProcMacro]>(symbol_name.as_bytes()) }?;
return Ok(Self { exported_macros: macros.to_vec() });
}
@ -45,6 +45,9 @@ impl ProcMacros {
macro_name: &str,
macro_body: &tt::Subtree,
attributes: Option<&tt::Subtree>,
def_site: TokenId,
call_site: TokenId,
mixed_site: TokenId,
) -> Result<tt::Subtree, crate::PanicMessage> {
let parsed_body = crate::server::TokenStream::with_subtree(macro_body.clone());
@ -54,58 +57,76 @@ impl ProcMacros {
for proc_macro in &self.exported_macros {
match proc_macro {
proc_macro::bridge::client::ProcMacro::CustomDerive {
trait_name, client, ..
} if *trait_name == macro_name => {
let res = client.run(
&proc_macro::bridge::server::SameThread,
crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER },
parsed_body,
true,
);
return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from);
}
proc_macro::bridge::client::ProcMacro::Bang { name, client }
if *name == macro_name =>
bridge::client::ProcMacro::CustomDerive { trait_name, client, .. }
if *trait_name == macro_name =>
{
let res = client.run(
&proc_macro::bridge::server::SameThread,
crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER },
&bridge::server::SameThread,
crate::server::RustAnalyzer {
interner: &SYMBOL_INTERNER,
call_site,
def_site,
mixed_site,
},
parsed_body,
true,
false,
);
return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from);
return res
.map(|it| it.into_subtree(call_site))
.map_err(crate::PanicMessage::from);
}
proc_macro::bridge::client::ProcMacro::Attr { name, client }
if *name == macro_name =>
{
bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
let res = client.run(
&proc_macro::bridge::server::SameThread,
crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER },
&bridge::server::SameThread,
crate::server::RustAnalyzer {
interner: &SYMBOL_INTERNER,
call_site,
def_site,
mixed_site,
},
parsed_body,
false,
);
return res
.map(|it| it.into_subtree(call_site))
.map_err(crate::PanicMessage::from);
}
bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
let res = client.run(
&bridge::server::SameThread,
crate::server::RustAnalyzer {
interner: &SYMBOL_INTERNER,
call_site,
def_site,
mixed_site,
},
parsed_attributes,
parsed_body,
true,
false,
);
return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from);
return res
.map(|it| it.into_subtree(call_site))
.map_err(crate::PanicMessage::from);
}
_ => continue,
}
}
Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into())
Err(bridge::PanicMessage::String("Nothing to expand".to_string()).into())
}
pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
self.exported_macros
.iter()
.map(|proc_macro| match proc_macro {
proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
(trait_name.to_string(), ProcMacroKind::CustomDerive)
}
proc_macro::bridge::client::ProcMacro::Bang { name, .. } => {
bridge::client::ProcMacro::Bang { name, .. } => {
(name.to_string(), ProcMacroKind::FuncLike)
}
proc_macro::bridge::client::ProcMacro::Attr { name, .. } => {
bridge::client::ProcMacro::Attr { name, .. } => {
(name.to_string(), ProcMacroKind::Attr)
}
})

View file

@ -11,6 +11,7 @@
use proc_macro::bridge::{self, server};
mod token_stream;
use proc_macro_api::msg::TokenId;
pub use token_stream::TokenStream;
use token_stream::TokenStreamBuilder;
@ -43,6 +44,9 @@ pub struct FreeFunctions;
pub struct RustAnalyzer {
// FIXME: store span information here.
pub(crate) interner: SymbolInternerRef,
pub call_site: TokenId,
pub def_site: TokenId,
pub mixed_site: TokenId,
}
impl server::Types for RustAnalyzer {
@ -69,7 +73,7 @@ impl server::FreeFunctions for RustAnalyzer {
kind: bridge::LitKind::Err,
symbol: Symbol::intern(self.interner, s),
suffix: None,
span: tt::TokenId::unspecified(),
span: self.call_site,
})
}
@ -83,7 +87,7 @@ impl server::TokenStream for RustAnalyzer {
stream.is_empty()
}
fn from_str(&mut self, src: &str) -> Self::TokenStream {
src.parse().expect("cannot parse string")
Self::TokenStream::from_str(src, self.call_site).expect("cannot parse string")
}
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
stream.to_string()
@ -280,7 +284,7 @@ impl server::Span for RustAnalyzer {
}
fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
// FIXME stub
tt::TokenId::unspecified()
self.call_site
}
/// Recent feature, not yet in the proc_macro
///
@ -317,15 +321,15 @@ impl server::Span for RustAnalyzer {
}
fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span {
// FIXME handle span
tt::TokenId::unspecified()
self.call_site
}
fn end(&mut self, _self_: Self::Span) -> Self::Span {
tt::TokenId::unspecified()
self.call_site
}
fn start(&mut self, _self_: Self::Span) -> Self::Span {
tt::TokenId::unspecified()
self.call_site
}
fn line(&mut self, _span: Self::Span) -> usize {
@ -349,9 +353,9 @@ impl server::Symbol for RustAnalyzer {
impl server::Server for RustAnalyzer {
fn globals(&mut self) -> bridge::ExpnGlobals<Self::Span> {
bridge::ExpnGlobals {
def_site: Span::unspecified(),
call_site: Span::unspecified(),
mixed_site: Span::unspecified(),
def_site: self.def_site,
call_site: self.call_site,
mixed_site: self.mixed_site,
}
}
@ -430,16 +434,16 @@ mod tests {
token_trees: vec![
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "struct".into(),
span: tt::TokenId::unspecified(),
span: tt::TokenId(0),
})),
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "T".into(),
span: tt::TokenId::unspecified(),
span: tt::TokenId(0),
})),
tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter {
open: tt::TokenId::unspecified(),
close: tt::TokenId::unspecified(),
open: tt::TokenId(0),
close: tt::TokenId(0),
kind: tt::DelimiterKind::Brace,
},
token_trees: vec![],
@ -452,33 +456,32 @@ mod tests {
#[test]
fn test_ra_server_from_str() {
use std::str::FromStr;
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter {
open: tt::TokenId::unspecified(),
close: tt::TokenId::unspecified(),
open: tt::TokenId(0),
close: tt::TokenId(0),
kind: tt::DelimiterKind::Parenthesis,
},
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "a".into(),
span: tt::TokenId::unspecified(),
span: tt::TokenId(0),
}))],
});
let t1 = TokenStream::from_str("(a)").unwrap();
let t1 = TokenStream::from_str("(a)", tt::TokenId(0)).unwrap();
assert_eq!(t1.token_trees.len(), 1);
assert_eq!(t1.token_trees[0], subtree_paren_a);
let t2 = TokenStream::from_str("(a);").unwrap();
let t2 = TokenStream::from_str("(a);", tt::TokenId(0)).unwrap();
assert_eq!(t2.token_trees.len(), 2);
assert_eq!(t2.token_trees[0], subtree_paren_a);
let underscore = TokenStream::from_str("_").unwrap();
let underscore = TokenStream::from_str("_", tt::TokenId(0)).unwrap();
assert_eq!(
underscore.token_trees[0],
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "_".into(),
span: tt::TokenId::unspecified(),
span: tt::TokenId(0),
}))
);
}

View file

@ -1,5 +1,7 @@
//! TokenStream implementation used by sysroot ABI
use proc_macro_api::msg::TokenId;
use crate::tt::{self, TokenTree};
#[derive(Debug, Default, Clone)]
@ -20,8 +22,15 @@ impl TokenStream {
}
}
pub(crate) fn into_subtree(self) -> tt::Subtree {
tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: self.token_trees }
pub(crate) fn into_subtree(self, call_site: TokenId) -> tt::Subtree {
tt::Subtree {
delimiter: tt::Delimiter {
open: call_site,
close: call_site,
kind: tt::DelimiterKind::Invisible,
},
token_trees: self.token_trees,
}
}
pub(super) fn is_empty(&self) -> bool {
@ -84,7 +93,7 @@ pub(super) struct TokenStreamBuilder {
/// pub(super)lic implementation details for the `TokenStream` type, such as iterators.
pub(super) mod token_stream {
use std::str::FromStr;
use proc_macro_api::msg::TokenId;
use super::{tt, TokenStream, TokenTree};
@ -109,14 +118,15 @@ pub(super) mod token_stream {
///
/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to
/// change these errors into `LexError`s later.
impl FromStr for TokenStream {
type Err = LexError;
#[rustfmt::skip]
impl /*FromStr for*/ TokenStream {
// type Err = LexError;
fn from_str(src: &str) -> Result<TokenStream, LexError> {
let (subtree, _token_map) =
mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
pub(crate) fn from_str(src: &str, call_site: TokenId) -> Result<TokenStream, LexError> {
let subtree =
mbe::parse_to_token_tree_static_span(call_site, src).ok_or("Failed to parse from mbe")?;
let subtree = subtree_replace_token_ids_with_unspecified(subtree);
let subtree = subtree_replace_token_ids_with_call_site(subtree,call_site);
Ok(TokenStream::with_subtree(subtree))
}
}
@ -127,43 +137,39 @@ pub(super) mod token_stream {
}
}
fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
fn subtree_replace_token_ids_with_call_site(
subtree: tt::Subtree,
call_site: TokenId,
) -> tt::Subtree {
tt::Subtree {
delimiter: tt::Delimiter {
open: tt::TokenId::UNSPECIFIED,
close: tt::TokenId::UNSPECIFIED,
..subtree.delimiter
},
delimiter: tt::Delimiter { open: call_site, close: call_site, ..subtree.delimiter },
token_trees: subtree
.token_trees
.into_iter()
.map(token_tree_replace_token_ids_with_unspecified)
.map(|it| token_tree_replace_token_ids_with_call_site(it, call_site))
.collect(),
}
}
fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree {
fn token_tree_replace_token_ids_with_call_site(
tt: tt::TokenTree,
call_site: TokenId,
) -> tt::TokenTree {
match tt {
tt::TokenTree::Leaf(leaf) => {
tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf))
tt::TokenTree::Leaf(leaf_replace_token_ids_with_call_site(leaf, call_site))
}
tt::TokenTree::Subtree(subtree) => {
tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree))
tt::TokenTree::Subtree(subtree_replace_token_ids_with_call_site(subtree, call_site))
}
}
}
fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
fn leaf_replace_token_ids_with_call_site(leaf: tt::Leaf, call_site: TokenId) -> tt::Leaf {
match leaf {
tt::Leaf::Literal(lit) => {
tt::Leaf::Literal(tt::Literal { span: tt::TokenId::unspecified(), ..lit })
}
tt::Leaf::Punct(punct) => {
tt::Leaf::Punct(tt::Punct { span: tt::TokenId::unspecified(), ..punct })
}
tt::Leaf::Ident(ident) => {
tt::Leaf::Ident(tt::Ident { span: tt::TokenId::unspecified(), ..ident })
}
tt::Leaf::Literal(lit) => tt::Leaf::Literal(tt::Literal { span: call_site, ..lit }),
tt::Leaf::Punct(punct) => tt::Leaf::Punct(tt::Punct { span: call_site, ..punct }),
tt::Leaf::Ident(ident) => tt::Leaf::Ident(tt::Ident { span: call_site, ..ident }),
}
}
}

View file

@ -8,7 +8,7 @@ use expect_test::expect;
#[test]
fn test_derive_empty() {
assert_expand("DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 4294967295 4294967295"]);
assert_expand("DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 1 1"]);
}
#[test]
@ -17,12 +17,12 @@ fn test_derive_error() {
"DeriveError",
r#"struct S;"#,
expect![[r##"
SUBTREE $$ 4294967295 4294967295
IDENT compile_error 4294967295
PUNCH ! [alone] 4294967295
SUBTREE () 4294967295 4294967295
LITERAL "#[derive(DeriveError)] struct S ;" 4294967295
PUNCH ; [alone] 4294967295"##]],
SUBTREE $$ 1 1
IDENT compile_error 1
PUNCH ! [alone] 1
SUBTREE () 1 1
LITERAL "#[derive(DeriveError)] struct S ;" 1
PUNCH ; [alone] 1"##]],
);
}
@ -32,14 +32,14 @@ fn test_fn_like_macro_noop() {
"fn_like_noop",
r#"ident, 0, 1, []"#,
expect![[r#"
SUBTREE $$ 4294967295 4294967295
IDENT ident 4294967295
PUNCH , [alone] 4294967295
LITERAL 0 4294967295
PUNCH , [alone] 4294967295
LITERAL 1 4294967295
PUNCH , [alone] 4294967295
SUBTREE [] 4294967295 4294967295"#]],
SUBTREE $$ 1 1
IDENT ident 1
PUNCH , [alone] 1
LITERAL 0 1
PUNCH , [alone] 1
LITERAL 1 1
PUNCH , [alone] 1
SUBTREE [] 1 1"#]],
);
}
@ -49,10 +49,10 @@ fn test_fn_like_macro_clone_ident_subtree() {
"fn_like_clone_tokens",
r#"ident, []"#,
expect![[r#"
SUBTREE $$ 4294967295 4294967295
IDENT ident 4294967295
PUNCH , [alone] 4294967295
SUBTREE [] 4294967295 4294967295"#]],
SUBTREE $$ 1 1
IDENT ident 1
PUNCH , [alone] 1
SUBTREE [] 1 1"#]],
);
}
@ -62,8 +62,8 @@ fn test_fn_like_macro_clone_raw_ident() {
"fn_like_clone_tokens",
"r#async",
expect![[r#"
SUBTREE $$ 4294967295 4294967295
IDENT r#async 4294967295"#]],
SUBTREE $$ 1 1
IDENT r#async 1"#]],
);
}
@ -73,14 +73,14 @@ fn test_fn_like_mk_literals() {
"fn_like_mk_literals",
r#""#,
expect![[r#"
SUBTREE $$ 4294967295 4294967295
LITERAL b"byte_string" 4294967295
LITERAL 'c' 4294967295
LITERAL "string" 4294967295
LITERAL 3.14f64 4294967295
LITERAL 3.14 4294967295
LITERAL 123i64 4294967295
LITERAL 123 4294967295"#]],
SUBTREE $$ 1 1
LITERAL b"byte_string" 1
LITERAL 'c' 1
LITERAL "string" 1
LITERAL 3.14f64 1
LITERAL 3.14 1
LITERAL 123i64 1
LITERAL 123 1"#]],
);
}
@ -90,9 +90,9 @@ fn test_fn_like_mk_idents() {
"fn_like_mk_idents",
r#""#,
expect![[r#"
SUBTREE $$ 4294967295 4294967295
IDENT standard 4294967295
IDENT r#raw 4294967295"#]],
SUBTREE $$ 1 1
IDENT standard 1
IDENT r#raw 1"#]],
);
}
@ -102,17 +102,17 @@ fn test_fn_like_macro_clone_literals() {
"fn_like_clone_tokens",
r#"1u16, 2_u32, -4i64, 3.14f32, "hello bridge""#,
expect![[r#"
SUBTREE $$ 4294967295 4294967295
LITERAL 1u16 4294967295
PUNCH , [alone] 4294967295
LITERAL 2_u32 4294967295
PUNCH , [alone] 4294967295
PUNCH - [alone] 4294967295
LITERAL 4i64 4294967295
PUNCH , [alone] 4294967295
LITERAL 3.14f32 4294967295
PUNCH , [alone] 4294967295
LITERAL "hello bridge" 4294967295"#]],
SUBTREE $$ 1 1
LITERAL 1u16 1
PUNCH , [alone] 1
LITERAL 2_u32 1
PUNCH , [alone] 1
PUNCH - [alone] 1
LITERAL 4i64 1
PUNCH , [alone] 1
LITERAL 3.14f32 1
PUNCH , [alone] 1
LITERAL "hello bridge" 1"#]],
);
}
@ -126,12 +126,12 @@ fn test_attr_macro() {
r#"mod m {}"#,
r#"some arguments"#,
expect![[r##"
SUBTREE $$ 4294967295 4294967295
IDENT compile_error 4294967295
PUNCH ! [alone] 4294967295
SUBTREE () 4294967295 4294967295
LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295
PUNCH ; [alone] 4294967295"##]],
SUBTREE $$ 1 1
IDENT compile_error 1
PUNCH ! [alone] 1
SUBTREE () 1 1
LITERAL "#[attr_error(some arguments)] mod m {}" 1
PUNCH ; [alone] 1"##]],
);
}

View file

@ -1,18 +1,18 @@
//! utils used in proc-macro tests
use expect_test::Expect;
use std::str::FromStr;
use proc_macro_api::msg::TokenId;
use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv};
fn parse_string(code: &str) -> Option<crate::server::TokenStream> {
fn parse_string(code: &str, call_site: TokenId) -> Option<crate::server::TokenStream> {
// This is a bit strange. We need to parse a string into a token stream into
// order to create a tt::SubTree from it in fixtures. `into_subtree` is
// implemented by all the ABIs we have so we arbitrarily choose one ABI to
// write a `parse_string` function for and use that. The tests don't really
// care which ABI we're using as the `into_subtree` function isn't part of
// the ABI and shouldn't change between ABI versions.
crate::server::TokenStream::from_str(code).ok()
crate::server::TokenStream::from_str(code, call_site).ok()
}
pub fn assert_expand(macro_name: &str, ra_fixture: &str, expect: Expect) {
@ -24,12 +24,24 @@ pub fn assert_expand_attr(macro_name: &str, ra_fixture: &str, attr_args: &str, e
}
fn assert_expand_impl(macro_name: &str, input: &str, attr: Option<&str>, expect: Expect) {
let def_site = TokenId(0);
let call_site = TokenId(1);
let mixed_site = TokenId(2);
let path = proc_macro_test_dylib_path();
let expander = dylib::Expander::new(&path).unwrap();
let fixture = parse_string(input).unwrap();
let attr = attr.map(|attr| parse_string(attr).unwrap().into_subtree());
let fixture = parse_string(input, call_site).unwrap();
let attr = attr.map(|attr| parse_string(attr, call_site).unwrap().into_subtree(call_site));
let res = expander.expand(macro_name, &fixture.into_subtree(), attr.as_ref()).unwrap();
let res = expander
.expand(
macro_name,
&fixture.into_subtree(call_site),
attr.as_ref(),
def_site,
call_site,
mixed_site,
)
.unwrap();
expect.assert_eq(&format!("{res:?}"));
}