]>
Commit | Line | Data |
---|---|---|
b039eaaf SL |
1 | // Copyright 2015 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 session::Session; | |
12 | ||
13 | use syntax::ast; | |
14 | use syntax::attr::AttrMetaMethods; | |
15 | use syntax::visit; | |
16 | use syntax::visit::Visitor; | |
17 | ||
18 | #[derive(Copy, Clone, PartialEq)] | |
19 | enum Target { | |
20 | Fn, | |
21 | Struct, | |
22 | Enum, | |
23 | Other, | |
24 | } | |
25 | ||
26 | impl Target { | |
27 | fn from_item(item: &ast::Item) -> Target { | |
28 | match item.node { | |
29 | ast::ItemFn(..) => Target::Fn, | |
30 | ast::ItemStruct(..) => Target::Struct, | |
31 | ast::ItemEnum(..) => Target::Enum, | |
32 | _ => Target::Other, | |
33 | } | |
34 | } | |
35 | } | |
36 | ||
37 | struct CheckAttrVisitor<'a> { | |
38 | sess: &'a Session, | |
39 | } | |
40 | ||
41 | impl<'a> CheckAttrVisitor<'a> { | |
42 | fn check_inline(&self, attr: &ast::Attribute, target: Target) { | |
43 | if target != Target::Fn { | |
92a42be0 | 44 | span_err!(self.sess, attr.span, E0518, "attribute should be applied to function"); |
b039eaaf SL |
45 | } |
46 | } | |
47 | ||
48 | fn check_repr(&self, attr: &ast::Attribute, target: Target) { | |
49 | let words = match attr.meta_item_list() { | |
50 | Some(words) => words, | |
51 | None => { | |
52 | return; | |
53 | } | |
54 | }; | |
55 | for word in words { | |
56 | let word: &str = &word.name(); | |
92a42be0 | 57 | let message = match word { |
b039eaaf SL |
58 | "C" => { |
59 | if target != Target::Struct && target != Target::Enum { | |
92a42be0 SL |
60 | "attribute should be applied to struct or enum" |
61 | } else { | |
62 | continue | |
b039eaaf SL |
63 | } |
64 | } | |
65 | "packed" | | |
66 | "simd" => { | |
67 | if target != Target::Struct { | |
92a42be0 SL |
68 | "attribute should be applied to struct" |
69 | } else { | |
70 | continue | |
b039eaaf SL |
71 | } |
72 | } | |
73 | "i8" | "u8" | "i16" | "u16" | | |
74 | "i32" | "u32" | "i64" | "u64" | | |
75 | "isize" | "usize" => { | |
76 | if target != Target::Enum { | |
92a42be0 SL |
77 | "attribute should be applied to enum" |
78 | } else { | |
79 | continue | |
b039eaaf SL |
80 | } |
81 | } | |
92a42be0 SL |
82 | _ => continue, |
83 | }; | |
84 | span_err!(self.sess, attr.span, E0517, "{}", message); | |
b039eaaf SL |
85 | } |
86 | } | |
87 | ||
88 | fn check_attribute(&self, attr: &ast::Attribute, target: Target) { | |
89 | let name: &str = &attr.name(); | |
90 | match name { | |
91 | "inline" => self.check_inline(attr, target), | |
92 | "repr" => self.check_repr(attr, target), | |
93 | _ => (), | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
98 | impl<'a, 'v> Visitor<'v> for CheckAttrVisitor<'a> { | |
99 | fn visit_item(&mut self, item: &ast::Item) { | |
100 | let target = Target::from_item(item); | |
101 | for attr in &item.attrs { | |
102 | self.check_attribute(attr, target); | |
103 | } | |
104 | } | |
105 | } | |
106 | ||
107 | pub fn check_crate(sess: &Session, krate: &ast::Crate) { | |
108 | visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate); | |
109 | } |