quote/
spanned.rs

1use crate::ToTokens;
2use proc_macro2::{Span, TokenStream};
3
4pub trait Spanned {
5    fn __span(&self) -> Span;
6}
7
8impl Spanned for Span {
9    fn __span(&self) -> Span {
10        *self
11    }
12}
13
14impl<T: ?Sized + ToTokens> Spanned for T {
15    fn __span(&self) -> Span {
16        join_spans(self.into_token_stream())
17    }
18}
19
20fn join_spans(tokens: TokenStream) -> Span {
21    let mut iter = tokens.into_iter().filter_map(|tt| {
22        // FIXME: This shouldn't be required, since optimally spans should
23        // never be invalid. This filter_map can probably be removed when
24        // https://github.com/rust-lang/rust/issues/43081 is resolved.
25        let span = tt.span();
26        let debug = format!("{:?}", span);
27        if debug.ends_with("bytes(0..0)") {
28            None
29        } else {
30            Some(span)
31        }
32    });
33
34    let first = match iter.next() {
35        Some(span) => span,
36        None => return Span::call_site(),
37    };
38
39    iter.fold(None, |_prev, next| Some(next))
40        .and_then(|last| first.join(last))
41        .unwrap_or(first)
42}