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
;
12 extern crate rustc_codegen_utils
;
15 use rustc_driver
::{driver, Compilation, CompilerCalls, RustcDefaultCalls}
;
16 use rustc_codegen_utils
::codegen_backend
::CodegenBackend
;
17 use rustc
::session
::{config, Session}
;
18 use rustc
::session
::config
::{ErrorOutputType, Input}
;
19 use std
::path
::PathBuf
;
20 use std
::process
::Command
;
23 struct ClippyCompilerCalls
{
24 default: RustcDefaultCalls
,
28 impl ClippyCompilerCalls
{
29 fn new(run_lints
: bool
) -> Self {
31 default: RustcDefaultCalls
,
37 impl<'a
> CompilerCalls
<'a
> for ClippyCompilerCalls
{
40 matches
: &getopts
::Matches
,
41 sopts
: &config
::Options
,
42 cfg
: &ast
::CrateConfig
,
43 descriptions
: &rustc_errors
::registry
::Registry
,
44 output
: ErrorOutputType
,
47 .early_callback(matches
, sopts
, cfg
, descriptions
, output
)
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
>)> {
59 .no_input(matches
, sopts
, cfg
, odir
, ofile
, descriptions
)
63 trans_crate
: &CodegenBackend
,
64 matches
: &getopts
::Matches
,
66 crate_stores
: &rustc
::middle
::cstore
::CrateStore
,
68 odir
: &Option
<PathBuf
>,
69 ofile
: &Option
<PathBuf
>,
72 .late_callback(trans_crate
, matches
, sess
, crate_stores
, input
, odir
, ofile
)
74 fn build_controller(&mut self, sess
: &Session
, matches
: &getopts
::Matches
) -> driver
::CompileController
<'a
> {
75 let mut control
= self.default.build_controller(sess
, matches
);
78 let old
= std
::mem
::replace(&mut control
.after_parse
.callback
, box |_
| {}
);
79 control
.after_parse
.callback
= Box
::new(move |state
| {
81 let mut registry
= rustc_plugin
::registry
::Registry
::new(
87 "at this compilation stage \
88 the crate must be parsed",
92 registry
.args_hidden
= Some(Vec
::new());
93 clippy_lints
::register_plugins(&mut registry
);
95 let rustc_plugin
::registry
::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
);
108 for pass
in late_lint_passes
{
109 ls
.register_late_pass(Some(sess
), true, pass
);
112 for (name
, to
) in lint_groups
{
113 ls
.register_group(Some(sess
), true, name
, to
);
116 sess
.plugin_llvm_passes
.borrow_mut().extend(llvm_passes
);
117 sess
.plugin_attributes
.borrow_mut().extend(attributes
);
127 #[allow(print_stdout)]
129 println
!(env
!("CARGO_PKG_VERSION"));
135 if std
::env
::args().any(|a
| a
== "--version" || a
== "-V") {
140 let sys_root
= option_env
!("SYSROOT")
142 .or_else(|| std
::env
::var("SYSROOT").ok())
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
)))
149 Command
::new("rustc")
154 .and_then(|out
| String
::from_utf8(out
.stdout
).ok())
155 .map(|s
| s
.trim().to_owned())
157 .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
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);
165 if orig_args
[1] == "rustc" {
166 // we still want to be able to invoke it normally though
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") {
178 .chain(Some("--sysroot".to_owned()))
179 .chain(Some(sys_root
))
183 // this check ensures that dependencies are built but not linted and the final
185 // linted but not built
186 let clippy_enabled
= env
::var("CLIPPY_TESTS")
188 .map_or(false, |val
| val
== "true")
189 || orig_args
.iter().any(|s
| s
== "--emit=dep-info,metadata");
192 args
.extend_from_slice(&["--cfg".to_owned(), r
#"feature="cargo-clippy""#.to_owned()]);
193 if let Ok(extra_args
) = env
::var("CLIPPY_ARGS") {
194 args
.extend(extra_args
.split("__CLIPPY_HACKERY__").filter(|s
| !s
.is_empty()).map(str::to_owned
));
198 let mut ccc
= ClippyCompilerCalls
::new(clippy_enabled
);
199 rustc_driver
::run(move || rustc_driver
::run_compiler(&args
, &mut ccc
, None
, None
));