blob: c844fc7b10db5cb5436e4f96e8ba267813a90409 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnaya9221302018-01-06 18:20:54 -08009//! A trait that can provide the `Span` of the complete contents of a syntax
10//! tree node.
11//!
David Tolnay461d98e2018-01-07 11:07:19 -080012//! *This module is available if Syn is built with both the `"parsing"` and
13//! `"printing"` features.*
14//!
David Tolnaya9221302018-01-06 18:20:54 -080015//! # Example
16//!
17//! Suppose in a procedural macro we have a [`Type`] that we want to assert
18//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
19//! of a struct for which we are deriving a trait implementation, and we need to
20//! be able to pass a reference to one of those fields across threads.
21//!
22//! [`Type`]: ../enum.Type.html
23//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
24//!
25//! If the field type does *not* implement `Sync` as required, we want the
26//! compiler to report an error pointing out exactly which type it was.
27//!
28//! The following macro code takes a variable `ty` of type `Type` and produces a
29//! static assertion that `Sync` is implemented for that type.
30//!
31//! ```
David Tolnay0a6deb22018-01-06 18:26:05 -080032//! #[macro_use]
33//! extern crate quote;
34//!
35//! extern crate syn;
36//! extern crate proc_macro;
37//! extern crate proc_macro2;
38//!
39//! use syn::Type;
40//! use syn::spanned::Spanned;
41//! use proc_macro::TokenStream;
42//! use proc_macro2::Span;
43//!
44//! # const IGNORE_TOKENS: &str = stringify! {
45//! #[proc_macro_derive(MyMacro)]
46//! # };
47//! pub fn my_macro(input: TokenStream) -> TokenStream {
48//! # let ty = get_a_type();
49//! /* ... */
50//!
51//! let def_site = Span::def_site();
52//! let ty_span = ty.span().resolved_at(def_site);
53//! let assert_sync = quote_spanned! {ty_span=>
54//! struct _AssertSync where #ty: Sync;
55//! };
56//!
57//! /* ... */
58//! # input
59//! }
David Tolnaya9221302018-01-06 18:20:54 -080060//! #
David Tolnay0a6deb22018-01-06 18:26:05 -080061//! # fn get_a_type() -> Type {
62//! # unimplemented!()
David Tolnaya9221302018-01-06 18:20:54 -080063//! # }
64//! #
65//! # fn main() {}
66//! ```
67//!
68//! By inserting this `assert_sync` fragment into the output code generated by
69//! our macro, the user's code will fail to compile if `ty` does not implement
70//! `Sync`. The errors they would see look like the following.
71//!
72//! ```text
73//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
74//! --> src/main.rs:10:21
75//! |
76//! 10 | bad_field: *const i32,
77//! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
78//! ```
79//!
80//! In this technique, using the `Type`'s span for the error message makes the
81//! error appear in the correct place underlining the right type. But it is
82//! **incredibly important** that the span for the assertion is **resolved** at
83//! the procedural macro definition site rather than at the `Type`'s span. This
84//! way we guarantee that it refers to the `Sync` trait that we expect. If the
85//! assertion were **resolved** at the same place that `ty` is resolved, the
86//! user could circumvent the check by defining their own `Sync` trait that is
87//! implemented for their type.
88
David Tolnayf790b612017-12-31 18:46:57 -050089use proc_macro2::{Span, TokenStream};
David Tolnay61037c62018-01-05 16:21:03 -080090use quote::{ToTokens, Tokens};
David Tolnayf790b612017-12-31 18:46:57 -050091
David Tolnaya9221302018-01-06 18:20:54 -080092/// A trait that can provide the `Span` of the complete contents of a syntax
93/// tree node.
94///
95/// This trait is automatically implemented for all types that implement
96/// [`ToTokens`] from the `quote` crate.
97///
98/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
99///
100/// See the [module documentation] for an example.
101///
102/// [module documentation]: index.html
David Tolnay461d98e2018-01-07 11:07:19 -0800103///
104/// *This trait is available if Syn is built with both the `"parsing"` and
105/// `"printing"` features.*
David Tolnayf790b612017-12-31 18:46:57 -0500106pub trait Spanned {
David Tolnaya9221302018-01-06 18:20:54 -0800107 /// Returns a `Span` covering the complete contents of this syntax tree
108 /// node, or [`Span::call_site()`] if this node is empty.
109 ///
110 /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.1/proc_macro2/struct.Span.html#method.call_site
David Tolnayf790b612017-12-31 18:46:57 -0500111 fn span(&self) -> Span;
112}
113
114impl<T> Spanned for T
115where
116 T: ToTokens,
117{
David Tolnay4d942b42018-01-02 22:14:04 -0800118 #[cfg(procmacro2_semver_exempt)]
David Tolnayf790b612017-12-31 18:46:57 -0500119 fn span(&self) -> Span {
120 let mut tokens = Tokens::new();
121 self.to_tokens(&mut tokens);
122 let token_stream = TokenStream::from(tokens);
123 let mut iter = token_stream.into_iter();
124 let mut span = match iter.next() {
125 Some(tt) => tt.span,
126 None => {
127 return Span::call_site();
128 }
129 };
130 for tt in iter {
131 if let Some(joined) = span.join(tt.span) {
132 span = joined;
133 }
134 }
135 span
136 }
David Tolnay4d942b42018-01-02 22:14:04 -0800137
138 #[cfg(not(procmacro2_semver_exempt))]
139 fn span(&self) -> Span {
140 let mut tokens = Tokens::new();
141 self.to_tokens(&mut tokens);
142 let token_stream = TokenStream::from(tokens);
143 let mut iter = token_stream.into_iter();
144
145 // We can't join spans without procmacro2_semver_exempt so just grab the
146 // first one.
147 match iter.next() {
148 Some(tt) => tt.span,
149 None => Span::call_site(),
150 }
151 }
David Tolnayf790b612017-12-31 18:46:57 -0500152}