]> git.proxmox.com Git - rustc.git/blame - src/tools/tidy/src/features.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / tools / tidy / src / features.rs
CommitLineData
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
20use std::collections::HashMap;
21use std::fs::File;
22use std::io::prelude::*;
23use std::path::Path;
24
25const STATUSES: &'static [&'static str] = &[
26 "Active", "Deprecated", "Removed", "Accepted",
27];
28
29struct Feature {
30 name: String,
31 since: String,
32 status: String,
33}
34
35struct LibFeature {
36 level: String,
37 since: String,
38}
39
40pub fn check(path: &Path, bad: &mut bool) {
41 let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
42 let mut lib_features = HashMap::<String, LibFeature>::new();
43
44 let mut contents = String::new();
45 super::walk(path,
46 &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
47 &mut |file| {
48 let filename = file.file_name().unwrap().to_string_lossy();
5bcae85e
SL
49 if !filename.ends_with(".rs") || filename == "features.rs" ||
50 filename == "diagnostic_list.rs" {
a7813a04
XL
51 return
52 }
53
54 contents.truncate(0);
55 t!(t!(File::open(file)).read_to_string(&mut contents));
56
57 for (i, line) in contents.lines().enumerate() {
58 let mut err = |msg: &str| {
59 println!("{}:{}: {}", file.display(), i + 1, msg);
60 *bad = true;
61 };
62 let level = if line.contains("[unstable(") {
63 "unstable"
64 } else if line.contains("[stable(") {
65 "stable"
66 } else {
67 continue
68 };
69 let feature_name = match find_attr_val(line, "feature") {
70 Some(name) => name,
71 None => {
72 err("malformed stability attribute");
73 continue
74 }
75 };
76 let since = match find_attr_val(line, "since") {
77 Some(name) => name,
78 None if level == "stable" => {
79 err("malformed stability attribute");
80 continue
81 }
82 None => "None",
83 };
84
85 if features.iter().any(|f| f.name == feature_name) {
86 err("duplicating a lang feature");
87 }
88 if let Some(ref s) = lib_features.get(feature_name) {
89 if s.level != level {
90 err("different stability level than before");
91 }
92 if s.since != since {
93 err("different `since` than before");
94 }
95 continue
96 }
97 lib_features.insert(feature_name.to_owned(), LibFeature {
98 level: level.to_owned(),
99 since: since.to_owned(),
100 });
101 }
102 });
103
104 if *bad {
105 return
106 }
107
108 let mut lines = Vec::new();
109 for feature in features {
110 lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
111 feature.name, "lang", feature.status, feature.since));
112 }
113 for (name, feature) in lib_features {
114 lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
115 name, "lib", feature.level, feature.since));
116 }
117
118 lines.sort();
119 for line in lines {
120 println!("* {}", line);
121 }
122}
123
124fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
125 line.find(attr).and_then(|i| {
126 line[i..].find("\"").map(|j| i + j + 1)
127 }).and_then(|i| {
128 line[i..].find("\"").map(|j| (i, i + j))
129 }).map(|(i, j)| {
130 &line[i..j]
131 })
132}
133
134fn collect_lang_features(path: &Path) -> Vec<Feature> {
135 let mut contents = String::new();
136 t!(t!(File::open(path)).read_to_string(&mut contents));
137
138 let mut features = Vec::new();
139 for line in contents.lines().map(|l| l.trim()) {
140 if !STATUSES.iter().any(|s| line.starts_with(&format!("({}", s))) {
141 continue
142 }
143 let mut parts = line.split(",");
144 let status = match &parts.next().unwrap().trim().replace("(", "")[..] {
145 "active" => "unstable",
146 "removed" => "unstable",
147 "accepted" => "stable",
148 s => panic!("unknown status: {}", s),
149 };
150 let name = parts.next().unwrap().trim().to_owned();
151 let since = parts.next().unwrap().trim().replace("\"", "");
152
153 features.push(Feature {
154 name: name,
155 since: since,
156 status: status.to_owned(),
157 });
158 }
159 return features
160}