]> git.lizzy.rs Git - rust.git/blob - src/main.rs
manually fixing formatting at this point lol
[rust.git] / src / main.rs
1 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
2
3 use rustc_tools_util::VersionInfo;
4 use std::env;
5 use std::ffi::OsString;
6 use std::path::PathBuf;
7 use std::process::{self, Command};
8
9 const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
10
11 Usage:
12     cargo clippy [options] [--] [<opts>...]
13
14 Common options:
15     -h, --help               Print this message
16     -V, --version            Print version info and exit
17
18 Other options are the same as `cargo check`.
19
20 To allow or deny a lint from the command line you can use `cargo clippy --`
21 with:
22
23     -W --warn OPT       Set lint warnings
24     -A --allow OPT      Set lint allowed
25     -D --deny OPT       Set lint denied
26     -F --forbid OPT     Set lint forbidden
27
28 You can use tool lints to allow or deny lints from your code, eg.:
29
30     #[allow(clippy::needless_lifetimes)]
31 "#;
32
33 fn show_help() {
34     println!("{}", CARGO_CLIPPY_HELP);
35 }
36
37 fn show_version() {
38     let version_info = rustc_tools_util::get_version_info!();
39     println!("{}", version_info);
40 }
41
42 pub fn main() {
43     // Check for version and help flags even when invoked as 'cargo-clippy'
44     if env::args().any(|a| a == "--help" || a == "-h") {
45         show_help();
46         return;
47     }
48
49     if env::args().any(|a| a == "--version" || a == "-V") {
50         show_version();
51         return;
52     }
53
54     if let Err(code) = process(env::args().skip(2)) {
55         process::exit(code);
56     }
57 }
58
59 struct ClippyCmd {
60     unstable_options: bool,
61     cargo_subcommand: &'static str,
62     args: Vec<String>,
63     clippy_args: String,
64 }
65
66 impl ClippyCmd {
67     fn new<I>(mut old_args: I) -> Self
68     where
69         I: Iterator<Item = String>,
70     {
71         let mut cargo_subcommand = "check";
72         let mut unstable_options = false;
73         let mut args = vec![];
74
75         for arg in old_args.by_ref() {
76             match arg.as_str() {
77                 "--fix" => {
78                     cargo_subcommand = "fix";
79                     continue;
80                 },
81                 "--" => break,
82                 // Cover -Zunstable-options and -Z unstable-options
83                 s if s.ends_with("unstable-options") => unstable_options = true,
84                 _ => {},
85             }
86
87             args.push(arg);
88         }
89
90         if cargo_subcommand == "fix" && !unstable_options {
91             panic!("Usage of `--fix` requires `-Z unstable-options`");
92         }
93
94         // Run the dogfood tests directly on nightly cargo. This is required due
95         // to a bug in rustup.rs when running cargo on custom toolchains. See issue #3118.
96         if env::var_os("CLIPPY_DOGFOOD").is_some() && cfg!(windows) {
97             args.insert(0, "+nightly".to_string());
98         }
99
100         let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect();
101
102         ClippyCmd {
103             unstable_options,
104             cargo_subcommand,
105             args,
106             clippy_args,
107         }
108     }
109
110     fn path_env(&self) -> &'static str {
111         if self.unstable_options {
112             "RUSTC_WORKSPACE_WRAPPER"
113         } else {
114             "RUSTC_WRAPPER"
115         }
116     }
117
118     fn path(&self) -> PathBuf {
119         let mut path = env::current_exe()
120             .expect("current executable path invalid")
121             .with_file_name("clippy-driver");
122
123         if cfg!(windows) {
124             path.set_extension("exe");
125         }
126
127         path
128     }
129
130     fn target_dir() -> Option<(&'static str, OsString)> {
131         env::var_os("CLIPPY_DOGFOOD")
132             .map(|_| {
133                 env::var_os("CARGO_MANIFEST_DIR").map_or_else(
134                     || std::ffi::OsString::from("clippy_dogfood"),
135                     |d| {
136                         std::path::PathBuf::from(d)
137                             .join("target")
138                             .join("dogfood")
139                             .into_os_string()
140                     },
141                 )
142             })
143             .map(|p| ("CARGO_TARGET_DIR", p))
144     }
145
146     fn to_std_cmd(self) -> Command {
147         let mut cmd = Command::new("cargo");
148
149         cmd.env(self.path_env(), self.path())
150             .envs(ClippyCmd::target_dir())
151             .env("CLIPPY_ARGS", self.clippy_args)
152             .arg(self.cargo_subcommand)
153             .args(&self.args);
154
155         cmd
156     }
157 }
158
159 fn process<I>(old_args: I) -> Result<(), i32>
160 where
161     I: Iterator<Item = String>,
162 {
163     let cmd = ClippyCmd::new(old_args);
164
165     let mut cmd = cmd.to_std_cmd();
166
167     let exit_status = cmd
168         .spawn()
169         .expect("could not run cargo")
170         .wait()
171         .expect("failed to wait for cargo?");
172
173     if exit_status.success() {
174         Ok(())
175     } else {
176         Err(exit_status.code().unwrap_or(-1))
177     }
178 }
179
180 #[cfg(test)]
181 mod tests {
182     use super::*;
183
184     #[test]
185     #[should_panic]
186     fn fix_without_unstable() {
187         let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string);
188         let _ = ClippyCmd::new(args);
189     }
190
191     #[test]
192     fn fix_unstable() {
193         let args = "cargo clippy --fix -Zunstable-options"
194             .split_whitespace()
195             .map(ToString::to_string);
196         let cmd = ClippyCmd::new(args);
197         assert_eq!("fix", cmd.cargo_subcommand);
198         assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env());
199         assert!(cmd.args.iter().find(|arg| arg.ends_with("unstable-options")).is_some());
200     }
201
202     #[test]
203     fn check() {
204         let args = "cargo clippy".split_whitespace().map(ToString::to_string);
205         let cmd = ClippyCmd::new(args);
206         assert_eq!("check", cmd.cargo_subcommand);
207         assert_eq!("RUSTC_WRAPPER", cmd.path_env());
208     }
209
210     #[test]
211     fn check_unstable() {
212         let args = "cargo clippy -Zunstable-options"
213             .split_whitespace()
214             .map(ToString::to_string);
215         let cmd = ClippyCmd::new(args);
216         assert_eq!("check", cmd.cargo_subcommand);
217         assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env());
218     }
219 }