]> git.lizzy.rs Git - rust.git/blob - src/driver.rs
Merge pull request #3136 from mikerite/driver-rustc-arg-2
[rust.git] / src / driver.rs
1 // error-pattern:yummy
2 #![feature(box_syntax)]
3 #![feature(rustc_private)]
4 #![feature(tool_lints)]
5 #![allow(unknown_lints, clippy::missing_docs_in_private_items)]
6
7 use rustc_driver::{self, driver::CompileController, Compilation};
8 use rustc_plugin;
9 use std::path::Path;
10 use std::process::{exit, Command};
11
12 #[allow(clippy::print_stdout)]
13 fn show_version() {
14     println!(env!("CARGO_PKG_VERSION"));
15 }
16
17 pub fn main() {
18     exit(rustc_driver::run(move || {
19         use std::env;
20
21         if std::env::args().any(|a| a == "--version" || a == "-V") {
22             show_version();
23             exit(0);
24         }
25
26         let sys_root = option_env!("SYSROOT")
27             .map(String::from)
28             .or_else(|| std::env::var("SYSROOT").ok())
29             .or_else(|| {
30                 let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
31                 let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
32                 home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain)))
33             })
34             .or_else(|| {
35                 Command::new("rustc")
36                     .arg("--print")
37                     .arg("sysroot")
38                     .output()
39                     .ok()
40                     .and_then(|out| String::from_utf8(out.stdout).ok())
41                     .map(|s| s.trim().to_owned())
42             })
43             .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
44
45         // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
46         // We're invoking the compiler programmatically, so we ignore this/
47         let mut orig_args: Vec<String> = env::args().collect();
48         if orig_args.len() <= 1 {
49             std::process::exit(1);
50         }
51         if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) {
52             // we still want to be able to invoke it normally though
53             orig_args.remove(1);
54         }
55         // this conditional check for the --sysroot flag is there so users can call
56         // `clippy_driver` directly
57         // without having to pass --sysroot or anything
58         let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
59             orig_args.clone()
60         } else {
61             orig_args
62                 .clone()
63                 .into_iter()
64                 .chain(Some("--sysroot".to_owned()))
65                 .chain(Some(sys_root))
66                 .collect()
67         };
68
69         // this check ensures that dependencies are built but not linted and the final
70         // crate is
71         // linted but not built
72         let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true")
73             || orig_args.iter().any(|s| s == "--emit=dep-info,metadata");
74
75         if clippy_enabled {
76             args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
77             if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
78                 args.extend(
79                     extra_args
80                         .split("__CLIPPY_HACKERY__")
81                         .filter(|s| !s.is_empty())
82                         .map(str::to_owned),
83                 );
84             }
85         }
86
87         let mut controller = CompileController::basic();
88         if clippy_enabled {
89             controller.after_parse.callback = Box::new(move |state| {
90                 let mut registry = rustc_plugin::registry::Registry::new(
91                     state.session,
92                     state
93                         .krate
94                         .as_ref()
95                         .expect(
96                             "at this compilation stage \
97                             the crate must be parsed",
98                         )
99                         .span,
100                 );
101                 registry.args_hidden = Some(Vec::new());
102
103                 let conf = clippy_lints::read_conf(&registry);
104                 clippy_lints::register_plugins(&mut registry, &conf);
105
106                 let rustc_plugin::registry::Registry {
107                     early_lint_passes,
108                     late_lint_passes,
109                     lint_groups,
110                     llvm_passes,
111                     attributes,
112                     ..
113                 } = registry;
114                 let sess = &state.session;
115                 let mut ls = sess.lint_store.borrow_mut();
116                 for pass in early_lint_passes {
117                     ls.register_early_pass(Some(sess), true, pass);
118                 }
119                 for pass in late_lint_passes {
120                     ls.register_late_pass(Some(sess), true, pass);
121                 }
122
123                 for (name, (to, deprecated_name)) in lint_groups {
124                     ls.register_group(Some(sess), true, name, deprecated_name, to);
125                 }
126                 clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf);
127
128                 sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
129                 sess.plugin_attributes.borrow_mut().extend(attributes);
130             });
131         }
132         controller.compilation_done.stop = Compilation::Stop;
133
134         let args = args;
135         rustc_driver::run_compiler(&args, Box::new(controller), None, None)
136     }) as i32)
137 }