//! A trait that can provide the `Span` of the complete contents of a syntax //! tree node. //! //! *This module is available if Syn is built with both the `"parsing"` and //! `"printing"` features.* //! //! # Example //! //! Suppose in a procedural macro we have a [`Type`] that we want to assert //! implements the [`Sync`] trait. Maybe this is the type of one of the fields //! of a struct for which we are deriving a trait implementation, and we need to //! be able to pass a reference to one of those fields across threads. //! //! [`Type`]: ../enum.Type.html //! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html //! //! If the field type does *not* implement `Sync` as required, we want the //! compiler to report an error pointing out exactly which type it was. //! //! The following macro code takes a variable `ty` of type `Type` and produces a //! static assertion that `Sync` is implemented for that type. //! //! ```edition2018 //! # extern crate proc_macro; //! # //! use proc_macro::TokenStream; //! use proc_macro2::Span; //! use quote::quote_spanned; //! use syn::Type; //! use syn::spanned::Spanned; //! //! # const IGNORE_TOKENS: &str = stringify! { //! #[proc_macro_derive(MyMacro)] //! # }; //! pub fn my_macro(input: TokenStream) -> TokenStream { //! # let ty = get_a_type(); //! /* ... */ //! //! let assert_sync = quote_spanned! {ty.span()=> //! struct _AssertSync where #ty: Sync; //! }; //! //! /* ... */ //! # input //! } //! # //! # fn get_a_type() -> Type { //! # unimplemented!() //! # } //! ``` //! //! By inserting this `assert_sync` fragment into the output code generated by //! our macro, the user's code will fail to compile if `ty` does not implement //! `Sync`. The errors they would see look like the following. //! //! ```text //! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied //! --> src/main.rs:10:21 //! | //! 10 | bad_field: *const i32, //! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely //! ``` //! //! In this technique, using the `Type`'s span for the error message makes the //! error appear in the correct place underlining the right type. use proc_macro2::{Span, TokenStream}; use quote::ToTokens; /// A trait that can provide the `Span` of the complete contents of a syntax /// tree node. /// /// This trait is automatically implemented for all types that implement /// [`ToTokens`] from the `quote` crate. It is sealed and cannot be implemented /// outside of the Syn crate other than by implementing `ToTokens`. /// /// [`ToTokens`]: quote::ToTokens /// /// See the [module documentation] for an example. /// /// [module documentation]: self /// /// *This trait is available if Syn is built with both the `"parsing"` and /// `"printing"` features.* pub trait Spanned: private::Sealed { /// Returns a `Span` covering the complete contents of this syntax tree /// node, or [`Span::call_site()`] if this node is empty. /// /// [`Span::call_site()`]: proc_macro2::Span::call_site fn span(&self) -> Span; } mod private { use quote::ToTokens; pub trait Sealed {} impl Sealed for T {} } impl Spanned for T where T: ToTokens, { fn span(&self) -> Span { join_spans(self.into_token_stream()) } } fn join_spans(tokens: TokenStream) -> Span { let mut iter = tokens.into_iter().filter_map(|tt| { // FIXME: This shouldn't be required, since optimally spans should // never be invalid. This filter_map can probably be removed when // https://github.com/rust-lang/rust/issues/43081 is resolved. let span = tt.span(); let debug = format!("{:?}", span); if debug.ends_with("bytes(0..0)") { None } else { Some(span) } }); let mut joined = match iter.next() { Some(span) => span, None => return Span::call_site(), }; #[cfg(procmacro2_semver_exempt)] { for next in iter { if let Some(span) = joined.join(next) { joined = span; } } } #[cfg(not(procmacro2_semver_exempt))] { // We can't join spans without procmacro2_semver_exempt so just grab the // first one. joined = joined; } joined }