]>
Commit | Line | Data |
---|---|---|
abe05a73 XL |
1 | // error-pattern:yummy |
2 | #![feature(box_syntax)] | |
3 | #![feature(rustc_private)] | |
4 | #![allow(unknown_lints, missing_docs_in_private_items)] | |
5 | ||
6 | extern crate clippy_lints; | |
7 | extern crate getopts; | |
8 | extern crate rustc; | |
9 | extern crate rustc_driver; | |
10 | extern crate rustc_errors; | |
11 | extern crate rustc_plugin; | |
2c00a5a8 | 12 | extern crate rustc_trans_utils; |
abe05a73 XL |
13 | extern crate syntax; |
14 | ||
15 | use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; | |
2c00a5a8 XL |
16 | use rustc_trans_utils::trans_crate::TransCrate; |
17 | use rustc::session::{config, Session}; | |
abe05a73 XL |
18 | use rustc::session::config::{ErrorOutputType, Input}; |
19 | use std::path::PathBuf; | |
20 | use std::process::Command; | |
21 | use syntax::ast; | |
22 | ||
23 | struct ClippyCompilerCalls { | |
24 | default: RustcDefaultCalls, | |
25 | run_lints: bool, | |
26 | } | |
27 | ||
28 | impl ClippyCompilerCalls { | |
29 | fn new(run_lints: bool) -> Self { | |
30 | Self { | |
31 | default: RustcDefaultCalls, | |
32 | run_lints: run_lints, | |
33 | } | |
34 | } | |
35 | } | |
36 | ||
37 | impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { | |
38 | fn early_callback( | |
39 | &mut self, | |
40 | matches: &getopts::Matches, | |
41 | sopts: &config::Options, | |
42 | cfg: &ast::CrateConfig, | |
43 | descriptions: &rustc_errors::registry::Registry, | |
44 | output: ErrorOutputType, | |
45 | ) -> Compilation { | |
46 | self.default | |
47 | .early_callback(matches, sopts, cfg, descriptions, output) | |
48 | } | |
49 | fn no_input( | |
50 | &mut self, | |
51 | matches: &getopts::Matches, | |
52 | sopts: &config::Options, | |
53 | cfg: &ast::CrateConfig, | |
54 | odir: &Option<PathBuf>, | |
55 | ofile: &Option<PathBuf>, | |
56 | descriptions: &rustc_errors::registry::Registry, | |
57 | ) -> Option<(Input, Option<PathBuf>)> { | |
58 | self.default | |
59 | .no_input(matches, sopts, cfg, odir, ofile, descriptions) | |
60 | } | |
61 | fn late_callback( | |
62 | &mut self, | |
2c00a5a8 | 63 | trans_crate: &TransCrate, |
abe05a73 XL |
64 | matches: &getopts::Matches, |
65 | sess: &Session, | |
66 | crate_stores: &rustc::middle::cstore::CrateStore, | |
67 | input: &Input, | |
68 | odir: &Option<PathBuf>, | |
69 | ofile: &Option<PathBuf>, | |
70 | ) -> Compilation { | |
71 | self.default | |
2c00a5a8 | 72 | .late_callback(trans_crate, matches, sess, crate_stores, input, odir, ofile) |
abe05a73 XL |
73 | } |
74 | fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { | |
75 | let mut control = self.default.build_controller(sess, matches); | |
76 | ||
77 | if self.run_lints { | |
78 | let old = std::mem::replace(&mut control.after_parse.callback, box |_| {}); | |
79 | control.after_parse.callback = Box::new(move |state| { | |
80 | { | |
81 | let mut registry = rustc_plugin::registry::Registry::new( | |
82 | state.session, | |
83 | state | |
84 | .krate | |
85 | .as_ref() | |
86 | .expect( | |
87 | "at this compilation stage \ | |
88 | the crate must be parsed", | |
89 | ) | |
90 | .span, | |
91 | ); | |
92 | registry.args_hidden = Some(Vec::new()); | |
93 | clippy_lints::register_plugins(&mut registry); | |
94 | ||
95 | let rustc_plugin::registry::Registry { | |
96 | early_lint_passes, | |
97 | late_lint_passes, | |
98 | lint_groups, | |
99 | llvm_passes, | |
100 | attributes, | |
101 | .. | |
102 | } = registry; | |
103 | let sess = &state.session; | |
104 | let mut ls = sess.lint_store.borrow_mut(); | |
105 | for pass in early_lint_passes { | |
106 | ls.register_early_pass(Some(sess), true, pass); | |
107 | } | |
108 | for pass in late_lint_passes { | |
109 | ls.register_late_pass(Some(sess), true, pass); | |
110 | } | |
111 | ||
112 | for (name, to) in lint_groups { | |
113 | ls.register_group(Some(sess), true, name, to); | |
114 | } | |
115 | ||
116 | sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); | |
117 | sess.plugin_attributes.borrow_mut().extend(attributes); | |
118 | } | |
119 | old(state); | |
120 | }); | |
121 | } | |
122 | ||
123 | control | |
124 | } | |
125 | } | |
126 | ||
127 | #[allow(print_stdout)] | |
128 | fn show_version() { | |
129 | println!("{}", env!("CARGO_PKG_VERSION")); | |
130 | } | |
131 | ||
132 | pub fn main() { | |
133 | use std::env; | |
134 | ||
135 | if std::env::args().any(|a| a == "--version" || a == "-V") { | |
136 | show_version(); | |
137 | return; | |
138 | } | |
139 | ||
140 | let sys_root = option_env!("SYSROOT") | |
141 | .map(String::from) | |
142 | .or_else(|| std::env::var("SYSROOT").ok()) | |
143 | .or_else(|| { | |
144 | let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); | |
145 | let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); | |
146 | home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) | |
147 | }) | |
148 | .or_else(|| { | |
149 | Command::new("rustc") | |
150 | .arg("--print") | |
151 | .arg("sysroot") | |
152 | .output() | |
153 | .ok() | |
154 | .and_then(|out| String::from_utf8(out.stdout).ok()) | |
155 | .map(|s| s.trim().to_owned()) | |
156 | }) | |
157 | .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); | |
158 | ||
2c00a5a8 XL |
159 | // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. |
160 | // We're invoking the compiler programmatically, so we ignore this/ | |
161 | let mut orig_args: Vec<String> = env::args().collect(); | |
162 | if orig_args.len() <= 1 { | |
163 | std::process::exit(1); | |
164 | } | |
165 | if orig_args[1] == "rustc" { | |
166 | // we still want to be able to invoke it normally though | |
167 | orig_args.remove(1); | |
168 | } | |
169 | // this conditional check for the --sysroot flag is there so users can call | |
170 | // `clippy_driver` directly | |
171 | // without having to pass --sysroot or anything | |
172 | let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { | |
173 | orig_args.clone() | |
174 | } else { | |
175 | orig_args | |
176 | .clone() | |
177 | .into_iter() | |
178 | .chain(Some("--sysroot".to_owned())) | |
179 | .chain(Some(sys_root)) | |
180 | .collect() | |
181 | }; | |
182 | ||
183 | // this check ensures that dependencies are built but not linted and the final | |
184 | // crate is | |
185 | // linted but not built | |
186 | let clippy_enabled = env::var("CLIPPY_TESTS") | |
187 | .ok() | |
188 | .map_or(false, |val| val == "true") | |
189 | || orig_args.iter().any(|s| s == "--emit=metadata"); | |
190 | ||
191 | if clippy_enabled { | |
192 | args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); | |
193 | } | |
abe05a73 | 194 | |
2c00a5a8 XL |
195 | let mut ccc = ClippyCompilerCalls::new(clippy_enabled); |
196 | rustc_driver::run(move || { | |
197 | rustc_driver::run_compiler(&args, &mut ccc, None, None) | |
198 | }); | |
abe05a73 | 199 | } |