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