]> git.lizzy.rs Git - rust.git/blob - src/spanned.rs
Merge pull request #2950 from CAD97/master
[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::ast;
12 use syntax::source_map::Span;
13
14 use macros::MacroArg;
15 use utils::{mk_sp, outer_attributes};
16
17 use std::cmp::max;
18
19 /// Spanned returns a span including attributes, if available.
20 pub trait Spanned {
21     fn span(&self) -> Span;
22 }
23
24 macro_rules! span_with_attrs_lo_hi {
25     ($this:ident, $lo:expr, $hi:expr) => {{
26         let attrs = outer_attributes(&$this.attrs);
27         if attrs.is_empty() {
28             mk_sp($lo, $hi)
29         } else {
30             mk_sp(attrs[0].span.lo(), $hi)
31         }
32     }};
33 }
34
35 macro_rules! span_with_attrs {
36     ($this:ident) => {
37         span_with_attrs_lo_hi!($this, $this.span.lo(), $this.span.hi())
38     };
39 }
40
41 macro_rules! implement_spanned {
42     ($this:ty) => {
43         impl Spanned for $this {
44             fn span(&self) -> Span {
45                 span_with_attrs!(self)
46             }
47         }
48     };
49 }
50
51 // Implement `Spanned` for structs with `attrs` field.
52 implement_spanned!(ast::Expr);
53 implement_spanned!(ast::Field);
54 implement_spanned!(ast::ForeignItem);
55 implement_spanned!(ast::Item);
56 implement_spanned!(ast::Local);
57 implement_spanned!(ast::TraitItem);
58 implement_spanned!(ast::ImplItem);
59
60 impl Spanned for ast::Stmt {
61     fn span(&self) -> Span {
62         match self.node {
63             ast::StmtKind::Local(ref local) => mk_sp(local.span().lo(), self.span.hi()),
64             ast::StmtKind::Item(ref item) => mk_sp(item.span().lo(), self.span.hi()),
65             ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
66                 mk_sp(expr.span().lo(), self.span.hi())
67             }
68             ast::StmtKind::Mac(ref mac) => {
69                 let (_, _, ref attrs) = **mac;
70                 if attrs.is_empty() {
71                     self.span
72                 } else {
73                     mk_sp(attrs[0].span.lo(), self.span.hi())
74                 }
75             }
76         }
77     }
78 }
79
80 impl Spanned for ast::Pat {
81     fn span(&self) -> Span {
82         self.span
83     }
84 }
85
86 impl Spanned for ast::Ty {
87     fn span(&self) -> Span {
88         self.span
89     }
90 }
91
92 impl Spanned for ast::Arm {
93     fn span(&self) -> Span {
94         let lo = if self.attrs.is_empty() {
95             self.pats[0].span.lo()
96         } else {
97             self.attrs[0].span.lo()
98         };
99         span_with_attrs_lo_hi!(self, lo, self.body.span.hi())
100     }
101 }
102
103 impl Spanned for ast::Arg {
104     fn span(&self) -> Span {
105         if ::items::is_named_arg(self) {
106             mk_sp(self.pat.span.lo(), self.ty.span.hi())
107         } else {
108             self.ty.span
109         }
110     }
111 }
112
113 impl Spanned for ast::GenericParam {
114     fn span(&self) -> Span {
115         let lo = if self.attrs.is_empty() {
116             self.ident.span.lo()
117         } else {
118             self.attrs[0].span.lo()
119         };
120         let hi = if self.bounds.is_empty() {
121             self.ident.span.hi()
122         } else {
123             self.bounds.last().unwrap().span().hi()
124         };
125         let ty_hi = if let ast::GenericParamKind::Type {
126             default: Some(ref ty),
127         } = self.kind
128         {
129             ty.span().hi()
130         } else {
131             hi
132         };
133         mk_sp(lo, max(hi, ty_hi))
134     }
135 }
136
137 impl Spanned for ast::StructField {
138     fn span(&self) -> Span {
139         span_with_attrs_lo_hi!(self, self.span.lo(), self.ty.span.hi())
140     }
141 }
142
143 impl Spanned for ast::WherePredicate {
144     fn span(&self) -> Span {
145         match *self {
146             ast::WherePredicate::BoundPredicate(ref p) => p.span,
147             ast::WherePredicate::RegionPredicate(ref p) => p.span,
148             ast::WherePredicate::EqPredicate(ref p) => p.span,
149         }
150     }
151 }
152
153 impl Spanned for ast::FunctionRetTy {
154     fn span(&self) -> Span {
155         match *self {
156             ast::FunctionRetTy::Default(span) => span,
157             ast::FunctionRetTy::Ty(ref ty) => ty.span,
158         }
159     }
160 }
161
162 impl Spanned for ast::GenericArg {
163     fn span(&self) -> Span {
164         match *self {
165             ast::GenericArg::Lifetime(ref lt) => lt.ident.span,
166             ast::GenericArg::Type(ref ty) => ty.span(),
167         }
168     }
169 }
170
171 impl Spanned for ast::GenericBound {
172     fn span(&self) -> Span {
173         match *self {
174             ast::GenericBound::Trait(ref ptr, _) => ptr.span,
175             ast::GenericBound::Outlives(ref l) => l.ident.span,
176         }
177     }
178 }
179
180 impl Spanned for MacroArg {
181     fn span(&self) -> Span {
182         match *self {
183             MacroArg::Expr(ref expr) => expr.span(),
184             MacroArg::Ty(ref ty) => ty.span(),
185             MacroArg::Pat(ref pat) => pat.span(),
186             MacroArg::Item(ref item) => item.span(),
187         }
188     }
189 }