]> git.lizzy.rs Git - rust.git/blob - src/spanned.rs
Merge pull request #2138 from topecongiro/comments-around-trait-bounds
[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::codemap::Span;
13
14 use macros::MacroArg;
15 use utils::{mk_sp, outer_attributes};
16
17 /// Spanned returns a span including attributes, if available.
18 pub trait Spanned {
19     fn span(&self) -> Span;
20 }
21
22 macro_rules! span_with_attrs_lo_hi {
23     ($this:ident, $lo:expr, $hi:expr) => {
24         {
25             let attrs = outer_attributes(&$this.attrs);
26             if attrs.is_empty() {
27                 mk_sp($lo, $hi)
28             } else {
29                 mk_sp(attrs[0].span.lo(), $hi)
30             }
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
58 impl Spanned for ast::Stmt {
59     fn span(&self) -> Span {
60         match self.node {
61             ast::StmtKind::Local(ref local) => mk_sp(local.span().lo(), self.span.hi()),
62             ast::StmtKind::Item(ref item) => mk_sp(item.span().lo(), self.span.hi()),
63             ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
64                 mk_sp(expr.span().lo(), self.span.hi())
65             }
66             ast::StmtKind::Mac(ref mac) => {
67                 let (_, _, ref attrs) = **mac;
68                 if attrs.is_empty() {
69                     self.span
70                 } else {
71                     mk_sp(attrs[0].span.lo(), self.span.hi())
72                 }
73             }
74         }
75     }
76 }
77
78 impl Spanned for ast::Pat {
79     fn span(&self) -> Span {
80         self.span
81     }
82 }
83
84 impl Spanned for ast::Ty {
85     fn span(&self) -> Span {
86         self.span
87     }
88 }
89
90 impl Spanned for ast::Arm {
91     fn span(&self) -> Span {
92         span_with_attrs_lo_hi!(self, self.pats[0].span.lo(), self.body.span.hi())
93     }
94 }
95
96 impl Spanned for ast::Arg {
97     fn span(&self) -> Span {
98         if ::items::is_named_arg(self) {
99             mk_sp(self.pat.span.lo(), self.ty.span.hi())
100         } else {
101             self.ty.span
102         }
103     }
104 }
105
106 impl Spanned for ast::StructField {
107     fn span(&self) -> Span {
108         span_with_attrs_lo_hi!(self, self.span.lo(), self.ty.span.hi())
109     }
110 }
111
112 impl Spanned for ast::WherePredicate {
113     fn span(&self) -> Span {
114         match *self {
115             ast::WherePredicate::BoundPredicate(ref p) => p.span,
116             ast::WherePredicate::RegionPredicate(ref p) => p.span,
117             ast::WherePredicate::EqPredicate(ref p) => p.span,
118         }
119     }
120 }
121
122 impl Spanned for ast::FunctionRetTy {
123     fn span(&self) -> Span {
124         match *self {
125             ast::FunctionRetTy::Default(span) => span,
126             ast::FunctionRetTy::Ty(ref ty) => ty.span,
127         }
128     }
129 }
130
131 impl Spanned for ast::TyParam {
132     fn span(&self) -> Span {
133         // Note that ty.span is the span for ty.ident, not the whole item.
134         let lo = if self.attrs.is_empty() {
135             self.span.lo()
136         } else {
137             self.attrs[0].span.lo()
138         };
139         if let Some(ref def) = self.default {
140             return mk_sp(lo, def.span.hi());
141         }
142         if self.bounds.is_empty() {
143             return mk_sp(lo, self.span.hi());
144         }
145         let hi = self.bounds[self.bounds.len() - 1].span().hi();
146         mk_sp(lo, hi)
147     }
148 }
149
150 impl Spanned for ast::TyParamBound {
151     fn span(&self) -> Span {
152         match *self {
153             ast::TyParamBound::TraitTyParamBound(ref ptr, _) => ptr.span,
154             ast::TyParamBound::RegionTyParamBound(ref l) => l.span,
155         }
156     }
157 }
158
159 impl Spanned for ast::LifetimeDef {
160     fn span(&self) -> Span {
161         let hi = if self.bounds.is_empty() {
162             self.lifetime.span.hi()
163         } else {
164             self.bounds[self.bounds.len() - 1].span.hi()
165         };
166         mk_sp(self.lifetime.span.lo(), hi)
167     }
168 }
169
170 impl Spanned for MacroArg {
171     fn span(&self) -> Span {
172         match *self {
173             MacroArg::Expr(ref expr) => expr.span(),
174             MacroArg::Ty(ref ty) => ty.span(),
175             MacroArg::Pat(ref pat) => pat.span(),
176         }
177     }
178 }