]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
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 | //! Tidy check to ensure that unstable features are all in order | |
12 | //! | |
13 | //! This check will ensure properties like: | |
14 | //! | |
15 | //! * All stability attributes look reasonably well formed | |
16 | //! * The set of library features is disjoint from the set of language features | |
17 | //! * Library features have at most one stability level | |
18 | //! * Library features have at most one `since` value | |
19 | ||
20 | use std::collections::HashMap; | |
c30ab7b3 | 21 | use std::fmt; |
a7813a04 XL |
22 | use std::fs::File; |
23 | use std::io::prelude::*; | |
24 | use std::path::Path; | |
25 | ||
c30ab7b3 SL |
26 | #[derive(PartialEq)] |
27 | enum Status { | |
28 | Stable, | |
29 | Unstable, | |
30 | } | |
31 | ||
32 | impl fmt::Display for Status { | |
33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
34 | let as_str = match *self { | |
35 | Status::Stable => "stable", | |
36 | Status::Unstable => "unstable", | |
37 | }; | |
38 | fmt::Display::fmt(as_str, f) | |
39 | } | |
40 | } | |
41 | ||
a7813a04 XL |
42 | |
43 | struct Feature { | |
44 | name: String, | |
c30ab7b3 | 45 | level: Status, |
a7813a04 | 46 | since: String, |
a7813a04 XL |
47 | } |
48 | ||
49 | struct LibFeature { | |
c30ab7b3 | 50 | level: Status, |
a7813a04 XL |
51 | since: String, |
52 | } | |
53 | ||
54 | pub fn check(path: &Path, bad: &mut bool) { | |
55 | let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs")); | |
c30ab7b3 | 56 | assert!(!features.is_empty()); |
a7813a04 XL |
57 | let mut lib_features = HashMap::<String, LibFeature>::new(); |
58 | ||
59 | let mut contents = String::new(); | |
60 | super::walk(path, | |
61 | &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), | |
62 | &mut |file| { | |
63 | let filename = file.file_name().unwrap().to_string_lossy(); | |
5bcae85e SL |
64 | if !filename.ends_with(".rs") || filename == "features.rs" || |
65 | filename == "diagnostic_list.rs" { | |
c30ab7b3 | 66 | return; |
a7813a04 XL |
67 | } |
68 | ||
69 | contents.truncate(0); | |
70 | t!(t!(File::open(file)).read_to_string(&mut contents)); | |
71 | ||
72 | for (i, line) in contents.lines().enumerate() { | |
73 | let mut err = |msg: &str| { | |
74 | println!("{}:{}: {}", file.display(), i + 1, msg); | |
75 | *bad = true; | |
76 | }; | |
77 | let level = if line.contains("[unstable(") { | |
c30ab7b3 | 78 | Status::Unstable |
a7813a04 | 79 | } else if line.contains("[stable(") { |
c30ab7b3 | 80 | Status::Stable |
a7813a04 | 81 | } else { |
c30ab7b3 | 82 | continue; |
a7813a04 XL |
83 | }; |
84 | let feature_name = match find_attr_val(line, "feature") { | |
85 | Some(name) => name, | |
86 | None => { | |
87 | err("malformed stability attribute"); | |
c30ab7b3 | 88 | continue; |
a7813a04 XL |
89 | } |
90 | }; | |
91 | let since = match find_attr_val(line, "since") { | |
92 | Some(name) => name, | |
c30ab7b3 | 93 | None if level == Status::Stable => { |
a7813a04 | 94 | err("malformed stability attribute"); |
c30ab7b3 | 95 | continue; |
a7813a04 XL |
96 | } |
97 | None => "None", | |
98 | }; | |
99 | ||
100 | if features.iter().any(|f| f.name == feature_name) { | |
101 | err("duplicating a lang feature"); | |
102 | } | |
103 | if let Some(ref s) = lib_features.get(feature_name) { | |
104 | if s.level != level { | |
105 | err("different stability level than before"); | |
106 | } | |
107 | if s.since != since { | |
108 | err("different `since` than before"); | |
109 | } | |
c30ab7b3 | 110 | continue; |
a7813a04 | 111 | } |
c30ab7b3 SL |
112 | lib_features.insert(feature_name.to_owned(), |
113 | LibFeature { | |
114 | level: level, | |
115 | since: since.to_owned(), | |
116 | }); | |
a7813a04 XL |
117 | } |
118 | }); | |
119 | ||
120 | if *bad { | |
c30ab7b3 | 121 | return; |
a7813a04 XL |
122 | } |
123 | ||
124 | let mut lines = Vec::new(); | |
125 | for feature in features { | |
126 | lines.push(format!("{:<32} {:<8} {:<12} {:<8}", | |
c30ab7b3 SL |
127 | feature.name, |
128 | "lang", | |
129 | feature.level, | |
130 | feature.since)); | |
a7813a04 XL |
131 | } |
132 | for (name, feature) in lib_features { | |
133 | lines.push(format!("{:<32} {:<8} {:<12} {:<8}", | |
c30ab7b3 SL |
134 | name, |
135 | "lib", | |
136 | feature.level, | |
137 | feature.since)); | |
a7813a04 XL |
138 | } |
139 | ||
140 | lines.sort(); | |
141 | for line in lines { | |
142 | println!("* {}", line); | |
143 | } | |
144 | } | |
145 | ||
146 | fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { | |
c30ab7b3 SL |
147 | line.find(attr) |
148 | .and_then(|i| line[i..].find('"').map(|j| i + j + 1)) | |
149 | .and_then(|i| line[i..].find('"').map(|j| (i, i + j))) | |
150 | .map(|(i, j)| &line[i..j]) | |
a7813a04 XL |
151 | } |
152 | ||
153 | fn collect_lang_features(path: &Path) -> Vec<Feature> { | |
154 | let mut contents = String::new(); | |
155 | t!(t!(File::open(path)).read_to_string(&mut contents)); | |
156 | ||
c30ab7b3 SL |
157 | contents.lines() |
158 | .filter_map(|line| { | |
159 | let mut parts = line.trim().split(","); | |
160 | let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) { | |
161 | Some("active") => Status::Unstable, | |
162 | Some("removed") => Status::Unstable, | |
163 | Some("accepted") => Status::Stable, | |
164 | _ => return None, | |
165 | }; | |
166 | let name = parts.next().unwrap().trim(); | |
167 | let since = parts.next().unwrap().trim().trim_matches('"'); | |
168 | Some(Feature { | |
169 | name: name.to_owned(), | |
170 | level: level, | |
171 | since: since.to_owned(), | |
172 | }) | |
173 | }) | |
174 | .collect() | |
a7813a04 | 175 | } |