Skip to content

Commit 50ffaca

Browse files
committed
Reduce the hackiness of cargo-clippy
1 parent ebc9891 commit 50ffaca

File tree

313 files changed

+649
-1101
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

313 files changed

+649
-1101
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ script:
2828
- cargo test --features debugging
2929
- mkdir -p ~/rust/cargo/bin
3030
- cp target/debug/cargo-clippy ~/rust/cargo/bin/cargo-clippy
31+
- cp target/debug/clippy-driver ~/rust/cargo/bin/clippy-driver
3132
- PATH=$PATH:~/rust/cargo/bin cargo clippy --all -- -D clippy
3233
- cd clippy_workspace_tests && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ..
3334
- cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../..

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ readme = "README.md"
1414
license = "MPL-2.0"
1515
keywords = ["clippy", "lint", "plugin"]
1616
categories = ["development-tools", "development-tools::cargo-plugins"]
17+
build = "build.rs"
1718

1819
[badges]
1920
travis-ci = { repository = "rust-lang-nursery/rust-clippy" }
@@ -29,6 +30,11 @@ name = "cargo-clippy"
2930
test = false
3031
path = "src/main.rs"
3132

33+
[[bin]]
34+
name = "clippy-driver"
35+
test = false
36+
path = "src/driver.rs"
37+
3238
[dependencies]
3339
# begin automatic update
3440
clippy_lints = { version = "0.0.165", path = "clippy_lints" }

build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use std::env;
2+
3+
fn main() {
4+
// Forward the profile to the main compilation
5+
println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
6+
// Don't rebuild even if nothing changed
7+
println!("cargo:rerun-if-changed=build.rs");
8+
}

src/driver.rs

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// error-pattern:yummy
2+
#![feature(box_syntax)]
3+
#![feature(rustc_private)]
4+
#![allow(unknown_lints, missing_docs_in_private_items)]
5+
6+
extern crate clippy_lints;
7+
extern crate getopts;
8+
extern crate rustc;
9+
extern crate rustc_driver;
10+
extern crate rustc_errors;
11+
extern crate rustc_plugin;
12+
extern crate syntax;
13+
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;
19+
use syntax::ast;
20+
21+
struct ClippyCompilerCalls {
22+
default: RustcDefaultCalls,
23+
run_lints: bool,
24+
}
25+
26+
impl ClippyCompilerCalls {
27+
fn new(run_lints: bool) -> Self {
28+
Self {
29+
default: RustcDefaultCalls,
30+
run_lints: run_lints,
31+
}
32+
}
33+
}
34+
35+
impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
36+
fn early_callback(
37+
&mut self,
38+
matches: &getopts::Matches,
39+
sopts: &config::Options,
40+
cfg: &ast::CrateConfig,
41+
descriptions: &rustc_errors::registry::Registry,
42+
output: ErrorOutputType,
43+
) -> Compilation {
44+
self.default
45+
.early_callback(matches, sopts, cfg, descriptions, output)
46+
}
47+
fn no_input(
48+
&mut self,
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>)> {
56+
self.default
57+
.no_input(matches, sopts, cfg, odir, ofile, descriptions)
58+
}
59+
fn late_callback(
60+
&mut self,
61+
matches: &getopts::Matches,
62+
sess: &Session,
63+
crate_stores: &rustc::middle::cstore::CrateStore,
64+
input: &Input,
65+
odir: &Option<PathBuf>,
66+
ofile: &Option<PathBuf>,
67+
) -> Compilation {
68+
self.default
69+
.late_callback(matches, sess, crate_stores, input, odir, ofile)
70+
}
71+
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
72+
let mut control = self.default.build_controller(sess, matches);
73+
74+
if self.run_lints {
75+
let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
76+
control.after_parse.callback = Box::new(move |state| {
77+
{
78+
let mut registry = rustc_plugin::registry::Registry::new(
79+
state.session,
80+
state
81+
.krate
82+
.as_ref()
83+
.expect(
84+
"at this compilation stage \
85+
the krate must be parsed",
86+
)
87+
.span,
88+
);
89+
registry.args_hidden = Some(Vec::new());
90+
clippy_lints::register_plugins(&mut registry);
91+
92+
let rustc_plugin::registry::Registry {
93+
early_lint_passes,
94+
late_lint_passes,
95+
lint_groups,
96+
llvm_passes,
97+
attributes,
98+
..
99+
} = 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);
104+
}
105+
for pass in late_lint_passes {
106+
ls.register_late_pass(Some(sess), true, pass);
107+
}
108+
109+
for (name, to) in lint_groups {
110+
ls.register_group(Some(sess), true, name, to);
111+
}
112+
113+
sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
114+
sess.plugin_attributes.borrow_mut().extend(attributes);
115+
}
116+
old(state);
117+
});
118+
}
119+
120+
control
121+
}
122+
}
123+
124+
#[allow(print_stdout)]
125+
fn show_version() {
126+
println!("{}", env!("CARGO_PKG_VERSION"));
127+
}
128+
129+
pub fn main() {
130+
use std::env;
131+
132+
if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
133+
panic!("yummy");
134+
}
135+
136+
if std::env::args().any(|a| a == "--version" || a == "-V") {
137+
show_version();
138+
return;
139+
}
140+
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+
let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
144+
format!("{}/toolchains/{}", home, toolchain)
145+
} else {
146+
option_env!("SYSROOT")
147+
.map(|s| s.to_owned())
148+
.or_else(|| {
149+
Command::new("rustc")
150+
.arg("--print")
151+
.arg("sysroot")
152+
.output()
153+
.ok()
154+
.and_then(|out| String::from_utf8(out.stdout).ok())
155+
.map(|s| s.trim().to_owned())
156+
})
157+
.expect(
158+
"need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
159+
)
160+
};
161+
162+
rustc_driver::in_rustc_thread(|| {
163+
// Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
164+
// We're invoking the compiler programatically, so we ignore this/
165+
let mut orig_args: Vec<String> = env::args().collect();
166+
if orig_args[1] == "rustc" {
167+
// we still want to be able to invoke it normally though
168+
orig_args.remove(1);
169+
}
170+
// this conditional check for the --sysroot flag is there so users can call
171+
// `clippy_driver` directly
172+
// without having to pass --sysroot or anything
173+
let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
174+
orig_args.clone()
175+
} else {
176+
orig_args.clone().into_iter()
177+
.chain(Some("--sysroot".to_owned()))
178+
.chain(Some(sys_root))
179+
.collect()
180+
};
181+
182+
// this check ensures that dependencies are built but not linted and the final
183+
// crate is
184+
// linted but not built
185+
let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") ||
186+
orig_args.iter().any(|s| s == "--emit=metadata");
187+
188+
if clippy_enabled {
189+
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
190+
}
191+
192+
let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
193+
let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
194+
if let Err(CompileIncomplete::Errored(_)) = result {
195+
std::process::exit(1);
196+
}
197+
}).expect("rustc_thread failed");
198+
}

0 commit comments

Comments
 (0)