2 #![feature(box_syntax)]
3 #![feature(rustc_private)]
4 #![allow(unknown_lints, missing_docs_in_private_items)]
6 extern crate clippy_lints
;
9 extern crate rustc_driver
;
10 extern crate rustc_errors
;
11 extern crate rustc_plugin
;
14 use rustc_driver
::{driver, Compilation, CompilerCalls, RustcDefaultCalls}
;
15 use rustc
::session
::{config, CompileIncomplete, Session}
;
16 use rustc
::session
::config
::{ErrorOutputType, Input}
;
17 use std
::path
::PathBuf
;
18 use std
::process
::Command
;
21 struct ClippyCompilerCalls
{
22 default: RustcDefaultCalls
,
26 impl ClippyCompilerCalls
{
27 fn new(run_lints
: bool
) -> Self {
29 default: RustcDefaultCalls
,
35 impl<'a
> CompilerCalls
<'a
> for ClippyCompilerCalls
{
38 matches
: &getopts
::Matches
,
39 sopts
: &config
::Options
,
40 cfg
: &ast
::CrateConfig
,
41 descriptions
: &rustc_errors
::registry
::Registry
,
42 output
: ErrorOutputType
,
45 .early_callback(matches
, sopts
, cfg
, descriptions
, output
)
49 matches
: &getopts
::Matches
,
50 sopts
: &config
::Options
,
51 cfg
: &ast
::CrateConfig
,
52 odir
: &Option
<PathBuf
>,
53 ofile
: &Option
<PathBuf
>,
54 descriptions
: &rustc_errors
::registry
::Registry
,
55 ) -> Option
<(Input
, Option
<PathBuf
>)> {
57 .no_input(matches
, sopts
, cfg
, odir
, ofile
, descriptions
)
61 matches
: &getopts
::Matches
,
63 crate_stores
: &rustc
::middle
::cstore
::CrateStore
,
65 odir
: &Option
<PathBuf
>,
66 ofile
: &Option
<PathBuf
>,
69 .late_callback(matches
, sess
, crate_stores
, input
, odir
, ofile
)
71 fn build_controller(&mut self, sess
: &Session
, matches
: &getopts
::Matches
) -> driver
::CompileController
<'a
> {
72 let mut control
= self.default.build_controller(sess
, matches
);
75 let old
= std
::mem
::replace(&mut control
.after_parse
.callback
, box |_
| {}
);
76 control
.after_parse
.callback
= Box
::new(move |state
| {
78 let mut registry
= rustc_plugin
::registry
::Registry
::new(
84 "at this compilation stage \
85 the crate must be parsed",
89 registry
.args_hidden
= Some(Vec
::new());
90 clippy_lints
::register_plugins(&mut registry
);
92 let rustc_plugin
::registry
::Registry
{
100 let sess
= &state
.session
;
101 let mut ls
= sess
.lint_store
.borrow_mut();
102 for pass
in early_lint_passes
{
103 ls
.register_early_pass(Some(sess
), true, pass
);
105 for pass
in late_lint_passes
{
106 ls
.register_late_pass(Some(sess
), true, pass
);
109 for (name
, to
) in lint_groups
{
110 ls
.register_group(Some(sess
), true, name
, to
);
113 sess
.plugin_llvm_passes
.borrow_mut().extend(llvm_passes
);
114 sess
.plugin_attributes
.borrow_mut().extend(attributes
);
124 #[allow(print_stdout)]
126 println
!("{}", env
!("CARGO_PKG_VERSION"));
132 if std
::env
::args().any(|a
| a
== "--version" || a
== "-V") {
137 let sys_root
= option_env
!("SYSROOT")
139 .or_else(|| std
::env
::var("SYSROOT").ok())
141 let home
= option_env
!("RUSTUP_HOME").or(option_env
!("MULTIRUST_HOME"));
142 let toolchain
= option_env
!("RUSTUP_TOOLCHAIN").or(option_env
!("MULTIRUST_TOOLCHAIN"));
143 home
.and_then(|home
| toolchain
.map(|toolchain
| format
!("{}/toolchains/{}", home
, toolchain
)))
146 Command
::new("rustc")
151 .and_then(|out
| String
::from_utf8(out
.stdout
).ok())
152 .map(|s
| s
.trim().to_owned())
154 .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
156 rustc_driver
::in_rustc_thread(|| {
157 // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
158 // We're invoking the compiler programmatically, so we ignore this/
159 let mut orig_args
: Vec
<String
> = env
::args().collect();
160 if orig_args
.len() <= 1 {
161 std
::process
::exit(1);
163 if orig_args
[1] == "rustc" {
164 // we still want to be able to invoke it normally though
167 // this conditional check for the --sysroot flag is there so users can call
168 // `clippy_driver` directly
169 // without having to pass --sysroot or anything
170 let mut args
: Vec
<String
> = if orig_args
.iter().any(|s
| s
== "--sysroot") {
176 .chain(Some("--sysroot".to_owned()))
177 .chain(Some(sys_root
))
181 // this check ensures that dependencies are built but not linted and the final
183 // linted but not built
184 let clippy_enabled
= env
::var("CLIPPY_TESTS")
186 .map_or(false, |val
| val
== "true")
187 || orig_args
.iter().any(|s
| s
== "--emit=metadata");
190 args
.extend_from_slice(&["--cfg".to_owned(), r
#"feature="cargo-clippy""#.to_owned()]);
193 let mut ccc
= ClippyCompilerCalls
::new(clippy_enabled
);
194 let (result
, _
) = rustc_driver
::run_compiler(&args
, &mut ccc
, None
, None
);
195 if let Err(CompileIncomplete
::Errored(_
)) = result
{
196 std
::process
::exit(1);
198 }).expect("rustc_thread failed");