]> git.lizzy.rs Git - rust.git/blob - src/spanned.rs
0.99.7
[rust.git] / src / spanned.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use syntax::{
12     ast, ptr,
13     source_map::{self, Span},
14 };
15
16 use macros::MacroArg;
17 use utils::{mk_sp, outer_attributes};
18
19 use std::cmp::max;
20
21 /// Spanned returns a span including attributes, if available.
22 pub trait Spanned {
23     fn span(&self) -> Span;
24 }
25
26 impl<T: Spanned> Spanned for ptr::P<T> {
27     fn span(&self) -> Span {
28         (**self).span()
29     }
30 }
31
32 impl<T> Spanned for source_map::Spanned<T> {
33     fn span(&self) -> Span {
34         self.span
35     }
36 }
37
38 macro_rules! span_with_attrs_lo_hi {
39     ($this:ident, $lo:expr, $hi:expr) => {{
40         let attrs = outer_attributes(&$this.attrs);
41         if attrs.is_empty() {
42             mk_sp($lo, $hi)
43         } else {
44             mk_sp(attrs[0].span.lo(), $hi)
45         }
46     }};
47 }
48
49 macro_rules! span_with_attrs {
50     ($this:ident) => {
51         span_with_attrs_lo_hi!($this, $this.span.lo(), $this.span.hi())
52     };
53 }
54
55 macro_rules! implement_spanned {
56     ($this:ty) => {
57         impl Spanned for $this {
58             fn span(&self) -> Span {
59                 span_with_attrs!(self)
60             }
61         }
62     };
63 }
64
65 // Implement `Spanned` for structs with `attrs` field.
66 implement_spanned!(ast::Expr);
67 implement_spanned!(ast::Field);
68 implement_spanned!(ast::ForeignItem);
69 implement_spanned!(ast::Item);
70 implement_spanned!(ast::Local);
71 implement_spanned!(ast::TraitItem);
72 implement_spanned!(ast::ImplItem);
73
74 impl Spanned for ast::Stmt {
75     fn span(&self) -> Span {
76         match self.node {
77             ast::StmtKind::Local(ref local) => mk_sp(local.span().lo(), self.span.hi()),
78             ast::StmtKind::Item(ref item) => mk_sp(item.span().lo(), self.span.hi()),
79             ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
80                 mk_sp(expr.span().lo(), self.span.hi())
81             }
82             ast::StmtKind::Mac(ref mac) => {
83                 let (_, _, ref attrs) = **mac;
84                 if attrs.is_empty() {
85                     self.span
86                 } else {
87                     mk_sp(attrs[0].span.lo(), self.span.hi())
88                 }
89             }
90         }
91     }
92 }
93
94 impl Spanned for ast::Pat {
95     fn span(&self) -> Span {
96         self.span
97     }
98 }
99
100 impl Spanned for ast::Ty {
101     fn span(&self) -> Span {
102         self.span
103     }
104 }
105
106 impl Spanned for ast::Arm {
107     fn span(&self) -> Span {
108         let lo = if self.attrs.is_empty() {
109             self.pats[0].span.lo()
110         } else {
111             self.attrs[0].span.lo()
112         };
113         span_with_attrs_lo_hi!(self, lo, self.body.span.hi())
114     }
115 }
116
117 impl Spanned for ast::Arg {
118     fn span(&self) -> Span {
119         if ::items::is_named_arg(self) {
120             mk_sp(self.pat.span.lo(), self.ty.span.hi())
121         } else {
122             self.ty.span
123         }
124     }
125 }
126
127 impl Spanned for ast::GenericParam {
128     fn span(&self) -> Span {
129         let lo = if self.attrs.is_empty() {
130             self.ident.span.lo()
131         } else {
132             self.attrs[0].span.lo()
133         };
134         let hi = if self.bounds.is_empty() {
135             self.ident.span.hi()
136         } else {
137             self.bounds.last().unwrap().span().hi()
138         };
139         let ty_hi = if let ast::GenericParamKind::Type {
140             default: Some(ref ty),
141         } = self.kind
142         {
143             ty.span().hi()
144         } else {
145             hi
146         };
147         mk_sp(lo, max(hi, ty_hi))
148     }
149 }
150
151 impl Spanned for ast::StructField {
152     fn span(&self) -> Span {
153         span_with_attrs_lo_hi!(self, self.span.lo(), self.ty.span.hi())
154     }
155 }
156
157 impl Spanned for ast::WherePredicate {
158     fn span(&self) -> Span {
159         match *self {
160             ast::WherePredicate::BoundPredicate(ref p) => p.span,
161             ast::WherePredicate::RegionPredicate(ref p) => p.span,
162             ast::WherePredicate::EqPredicate(ref p) => p.span,
163         }
164     }
165 }
166
167 impl Spanned for ast::FunctionRetTy {
168     fn span(&self) -> Span {
169         match *self {
170             ast::FunctionRetTy::Default(span) => span,
171             ast::FunctionRetTy::Ty(ref ty) => ty.span,
172         }
173     }
174 }
175
176 impl Spanned for ast::GenericArg {
177     fn span(&self) -> Span {
178         match *self {
179             ast::GenericArg::Lifetime(ref lt) => lt.ident.span,
180             ast::GenericArg::Type(ref ty) => ty.span(),
181         }
182     }
183 }
184
185 impl Spanned for ast::GenericBound {
186     fn span(&self) -> Span {
187         match *self {
188             ast::GenericBound::Trait(ref ptr, _) => ptr.span,
189             ast::GenericBound::Outlives(ref l) => l.ident.span,
190         }
191     }
192 }
193
194 impl Spanned for MacroArg {
195     fn span(&self) -> Span {
196         match *self {
197             MacroArg::Expr(ref expr) => expr.span(),
198             MacroArg::Ty(ref ty) => ty.span(),
199             MacroArg::Pat(ref pat) => pat.span(),
200             MacroArg::Item(ref item) => item.span(),
201         }
202     }
203 }