Skip to content

Commit 855b292

Browse files
committed
Merge pull request #681 from oli-obk/split
cargo clippy
2 parents dc75836 + 654154d commit 855b292

File tree

5 files changed

+185
-14
lines changed

5 files changed

+185
-14
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ script:
1818
- remark -f README.md > /dev/null
1919
- python util/update_lints.py -c
2020
- cargo build --features debugging
21-
- rm -rf target/ Cargo.lock
2221
- cargo test --features debugging
22+
- SYSROOT=~/rust cargo install
23+
- cargo clippy --lib -- -D clippy
2324

2425
after_success:
2526
# only test regex_macros if it compiles

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ keywords = ["clippy", "lint", "plugin"]
1616
[lib]
1717
name = "clippy"
1818
plugin = true
19+
test = false
20+
21+
[[bin]]
22+
name = "cargo-clippy"
23+
path = "src/lib.rs"
24+
test = false
1925

2026
[dependencies]
2127
regex-syntax = "0.3.0"

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/
173173

174174
## Usage
175175

176+
### As a Compiler Plugin
177+
176178
Compiler plugins are highly unstable and will only work with a nightly Rust for now.
177179
Since stable Rust is backwards compatible, you should be able to compile
178180
your stable programs with nightly Rust with clippy plugged in to circumvent
@@ -217,8 +219,28 @@ src/main.rs:8:5: 11:6 help: Try
217219
if let Some(y) = x { println!("{:?}", y) }
218220
```
219221

220-
An alternate way to use clippy is by compiling and using [`cargo clippy`](https://github.com/arcnmx/cargo-clippy),
221-
a custom cargo subcommand that runs clippy on a given project.
222+
### As a cargo subcommand (`cargo clippy`)
223+
224+
An alternate way to use clippy is by installing clippy through cargo as a cargo
225+
subcommand.
226+
227+
```terminal
228+
cargo install clippy
229+
```
230+
231+
Now you can run clippy by invoking `cargo clippy`, or
232+
`multirust run nightly cargo clippy` directly from a directory that is usually
233+
compiled with stable.
234+
235+
In case you are not using multirust, you need to set the environment flag
236+
`SYSROOT` during installation so clippy knows where to find `librustc` and
237+
similar crates.
238+
239+
```terminal
240+
SYSROOT=/path/to/rustc/sysroot cargo install clippy
241+
```
242+
243+
### Configuring clippy
222244

223245
You can add options to `allow`/`warn`/`deny`:
224246

@@ -234,6 +256,8 @@ You can add options to `allow`/`warn`/`deny`:
234256

235257
Note: `deny` produces errors instead of warnings
236258

259+
### Running clippy from the command line without installing
260+
237261
To have cargo compile your crate with clippy without needing `#![plugin(clippy)]`
238262
in your code, you can use:
239263

@@ -244,6 +268,8 @@ cargo rustc -- -L /path/to/clippy_so -Z extra-plugins=clippy
244268
*[Note](https://github.com/Manishearth/rust-clippy/wiki#a-word-of-warning):*
245269
Be sure that clippy was compiled with the same version of rustc that cargo invokes here!
246270

271+
### Optional dependency
272+
247273
If you want to make clippy an optional dependency, you can do the following:
248274

249275
In your `Cargo.toml`:

src/lib.rs

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,145 @@
99
#![allow(indexing_slicing, shadow_reuse, unknown_lints)]
1010
#![allow(float_arithmetic, integer_arithmetic)]
1111

12-
// this only exists to allow the "dogfood" integration test to work
13-
#[allow(dead_code)]
14-
#[allow(print_stdout)]
15-
fn main() {
16-
println!("What are you doing? Don't run clippy as an executable");
12+
extern crate rustc_driver;
13+
extern crate getopts;
14+
15+
use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation};
16+
use rustc::session::{config, Session};
17+
use rustc::session::config::{Input, ErrorOutputType};
18+
use syntax::diagnostics;
19+
use std::path::PathBuf;
20+
21+
struct ClippyCompilerCalls(RustcDefaultCalls);
22+
23+
impl std::default::Default for ClippyCompilerCalls {
24+
fn default() -> Self {
25+
Self::new()
26+
}
27+
}
28+
29+
impl ClippyCompilerCalls {
30+
fn new() -> Self {
31+
ClippyCompilerCalls(RustcDefaultCalls)
32+
}
33+
}
34+
35+
impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
36+
fn early_callback(&mut self,
37+
matches: &getopts::Matches,
38+
sopts: &config::Options,
39+
descriptions: &diagnostics::registry::Registry,
40+
output: ErrorOutputType)
41+
-> Compilation {
42+
self.0.early_callback(matches, sopts, descriptions, output)
43+
}
44+
fn no_input(&mut self,
45+
matches: &getopts::Matches,
46+
sopts: &config::Options,
47+
odir: &Option<PathBuf>,
48+
ofile: &Option<PathBuf>,
49+
descriptions: &diagnostics::registry::Registry)
50+
-> Option<(Input, Option<PathBuf>)> {
51+
self.0.no_input(matches, sopts, odir, ofile, descriptions)
52+
}
53+
fn late_callback(&mut self,
54+
matches: &getopts::Matches,
55+
sess: &Session,
56+
input: &Input,
57+
odir: &Option<PathBuf>,
58+
ofile: &Option<PathBuf>)
59+
-> Compilation {
60+
self.0.late_callback(matches, sess, input, odir, ofile)
61+
}
62+
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
63+
let mut control = self.0.build_controller(sess, matches);
64+
65+
let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
66+
control.after_parse.callback = Box::new(move |state| {
67+
{
68+
let mut registry = rustc_plugin::registry::Registry::new(state.session, state.krate.as_ref().expect("at this compilation stage the krate must be parsed"));
69+
registry.args_hidden = Some(Vec::new());
70+
plugin_registrar(&mut registry);
71+
72+
let rustc_plugin::registry::Registry { early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, mir_passes, .. } = registry;
73+
let sess = &state.session;
74+
let mut ls = sess.lint_store.borrow_mut();
75+
for pass in early_lint_passes {
76+
ls.register_early_pass(Some(sess), true, pass);
77+
}
78+
for pass in late_lint_passes {
79+
ls.register_late_pass(Some(sess), true, pass);
80+
}
81+
82+
for (name, to) in lint_groups {
83+
ls.register_group(Some(sess), true, name, to);
84+
}
85+
86+
sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
87+
sess.mir_passes.borrow_mut().extend(mir_passes);
88+
sess.plugin_attributes.borrow_mut().extend(attributes);
89+
}
90+
old(state);
91+
});
92+
93+
control
94+
}
95+
}
96+
97+
use std::path::Path;
98+
99+
pub fn main() {
100+
use std::env;
101+
102+
if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
103+
return;
104+
}
105+
106+
let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps");
107+
let sys_root = match (option_env!("MULTIRUST_HOME"), option_env!("MULTIRUST_TOOLCHAIN")) {
108+
(Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
109+
_ => option_env!("SYSROOT").expect("need to specify SYSROOT env var during clippy compilation or use multirust").to_owned(),
110+
};
111+
112+
if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
113+
let args = wrap_args(std::env::args().skip(2), dep_path, sys_root);
114+
let path = std::env::current_exe().expect("current executable path invalid");
115+
let run = std::process::Command::new("cargo")
116+
.args(&args)
117+
.env("RUSTC", path)
118+
.spawn().expect("could not run cargo")
119+
.wait().expect("failed to wait for cargo?")
120+
.success();
121+
assert!(run, "cargo rustc failed");
122+
} else {
123+
let args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
124+
env::args().collect()
125+
} else {
126+
env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect()
127+
};
128+
rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new());
129+
}
130+
}
131+
132+
fn wrap_args<P, I>(old_args: I, dep_path: P, sysroot: String) -> Vec<String>
133+
where P: AsRef<Path>, I: Iterator<Item=String> {
134+
135+
let mut args = vec!["rustc".to_owned()];
136+
137+
let mut found_dashes = false;
138+
for arg in old_args {
139+
found_dashes |= arg == "--";
140+
args.push(arg);
141+
}
142+
if !found_dashes {
143+
args.push("--".to_owned());
144+
}
145+
args.push("-L".to_owned());
146+
args.push(dep_path.as_ref().to_string_lossy().into_owned());
147+
args.push(String::from("--sysroot"));
148+
args.push(sysroot);
149+
args.push("-Zno-trans".to_owned());
150+
args
17151
}
18152

19153
#[macro_use]

tests/dogfood.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
#![feature(test)]
1+
#![feature(test, plugin)]
2+
#![plugin(clippy)]
3+
#![deny(clippy, clippy_pedantic)]
24

35
extern crate compiletest_rs as compiletest;
46
extern crate test;
57

6-
use std::env::var;
8+
use std::env::{var, set_var};
79
use std::path::PathBuf;
810
use test::TestPaths;
911

1012
#[test]
1113
fn dogfood() {
1214
let mut config = compiletest::default_config();
1315

14-
let cfg_mode = "run-pass".parse().ok().expect("Invalid mode");
16+
let cfg_mode = "run-pass".parse().expect("Invalid mode");
1517
let mut s = String::new();
1618
s.push_str(" -L target/debug/");
1719
s.push_str(" -L target/debug/deps");
1820
s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy");
1921
config.target_rustcflags = Some(s);
20-
if let Ok(name) = var::<&str>("TESTNAME") {
21-
let s : String = name.to_owned();
22-
config.filter = Some(s)
22+
if let Ok(name) = var("TESTNAME") {
23+
config.filter = Some(name.to_owned())
2324
}
2425

2526
config.mode = cfg_mode;
@@ -29,5 +30,8 @@ fn dogfood() {
2930
file: PathBuf::from("src/lib.rs"),
3031
relative_dir: PathBuf::new(),
3132
};
33+
34+
set_var("CLIPPY_DOGFOOD", "tastes like chicken");
35+
3236
compiletest::runtest::run(config, &paths);
3337
}

0 commit comments

Comments
 (0)