blob: 3ed46edc4ab6d2bdfc5b8303299faaa6d19378f9 [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 Tolnayf790b612017-12-31 18:46:57 -05009use proc_macro2::{Span, TokenStream};
David Tolnay61037c62018-01-05 16:21:03 -080010use quote::{ToTokens, Tokens};
David Tolnayf790b612017-12-31 18:46:57 -050011
12pub trait Spanned {
13 /// Returns a `Span` covering the complete contents of this AST node, or
14 /// `Span::call_site()` if this node is empty.
15 fn span(&self) -> Span;
16}
17
18impl<T> Spanned for T
19where
20 T: ToTokens,
21{
David Tolnay4d942b42018-01-02 22:14:04 -080022 #[cfg(procmacro2_semver_exempt)]
David Tolnayf790b612017-12-31 18:46:57 -050023 fn span(&self) -> Span {
24 let mut tokens = Tokens::new();
25 self.to_tokens(&mut tokens);
26 let token_stream = TokenStream::from(tokens);
27 let mut iter = token_stream.into_iter();
28 let mut span = match iter.next() {
29 Some(tt) => tt.span,
30 None => {
31 return Span::call_site();
32 }
33 };
34 for tt in iter {
35 if let Some(joined) = span.join(tt.span) {
36 span = joined;
37 }
38 }
39 span
40 }
David Tolnay4d942b42018-01-02 22:14:04 -080041
42 #[cfg(not(procmacro2_semver_exempt))]
43 fn span(&self) -> Span {
44 let mut tokens = Tokens::new();
45 self.to_tokens(&mut tokens);
46 let token_stream = TokenStream::from(tokens);
47 let mut iter = token_stream.into_iter();
48
49 // We can't join spans without procmacro2_semver_exempt so just grab the
50 // first one.
51 match iter.next() {
52 Some(tt) => tt.span,
53 None => Span::call_site(),
54 }
55 }
David Tolnayf790b612017-12-31 18:46:57 -050056}