cargo clippy subcommand

This commit is contained in:
Oliver Schneider 2016-02-17 18:16:29 +01:00
parent 488199d88f
commit 654154d8e7
No known key found for this signature in database
GPG key ID: 56D6EEA0FC67AC46
5 changed files with 185 additions and 14 deletions

View file

@ -18,8 +18,9 @@ script:
- remark -f README.md > /dev/null
- python util/update_lints.py -c
- cargo build --features debugging
- rm -rf target/ Cargo.lock
- cargo test --features debugging
- SYSROOT=~/rust cargo install
- cargo clippy --lib -- -D clippy
after_success:
# only test regex_macros if it compiles

View file

@ -16,6 +16,12 @@ keywords = ["clippy", "lint", "plugin"]
[lib]
name = "clippy"
plugin = true
test = false
[[bin]]
name = "cargo-clippy"
path = "src/lib.rs"
test = false
[dependencies]
regex-syntax = "0.3.0"

View file

@ -173,6 +173,8 @@ More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/
## Usage
### As a Compiler Plugin
Compiler plugins are highly unstable and will only work with a nightly Rust for now.
Since stable Rust is backwards compatible, you should be able to compile
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
if let Some(y) = x { println!("{:?}", y) }
```
An alternate way to use clippy is by compiling and using [`cargo clippy`](https://github.com/arcnmx/cargo-clippy),
a custom cargo subcommand that runs clippy on a given project.
### As a cargo subcommand (`cargo clippy`)
An alternate way to use clippy is by installing clippy through cargo as a cargo
subcommand.
```terminal
cargo install clippy
```
Now you can run clippy by invoking `cargo clippy`, or
`multirust run nightly cargo clippy` directly from a directory that is usually
compiled with stable.
In case you are not using multirust, you need to set the environment flag
`SYSROOT` during installation so clippy knows where to find `librustc` and
similar crates.
```terminal
SYSROOT=/path/to/rustc/sysroot cargo install clippy
```
### Configuring clippy
You can add options to `allow`/`warn`/`deny`:
@ -234,6 +256,8 @@ You can add options to `allow`/`warn`/`deny`:
Note: `deny` produces errors instead of warnings
### Running clippy from the command line without installing
To have cargo compile your crate with clippy without needing `#![plugin(clippy)]`
in your code, you can use:
@ -244,6 +268,8 @@ cargo rustc -- -L /path/to/clippy_so -Z extra-plugins=clippy
*[Note](https://github.com/Manishearth/rust-clippy/wiki#a-word-of-warning):*
Be sure that clippy was compiled with the same version of rustc that cargo invokes here!
### Optional dependency
If you want to make clippy an optional dependency, you can do the following:
In your `Cargo.toml`:

View file

@ -9,11 +9,145 @@
#![allow(indexing_slicing, shadow_reuse, unknown_lints)]
#![allow(float_arithmetic, integer_arithmetic)]
// this only exists to allow the "dogfood" integration test to work
#[allow(dead_code)]
#[allow(print_stdout)]
fn main() {
println!("What are you doing? Don't run clippy as an executable");
extern crate rustc_driver;
extern crate getopts;
use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation};
use rustc::session::{config, Session};
use rustc::session::config::{Input, ErrorOutputType};
use syntax::diagnostics;
use std::path::PathBuf;
struct ClippyCompilerCalls(RustcDefaultCalls);
impl std::default::Default for ClippyCompilerCalls {
fn default() -> Self {
Self::new()
}
}
impl ClippyCompilerCalls {
fn new() -> Self {
ClippyCompilerCalls(RustcDefaultCalls)
}
}
impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
fn early_callback(&mut self,
matches: &getopts::Matches,
sopts: &config::Options,
descriptions: &diagnostics::registry::Registry,
output: ErrorOutputType)
-> Compilation {
self.0.early_callback(matches, sopts, descriptions, output)
}
fn no_input(&mut self,
matches: &getopts::Matches,
sopts: &config::Options,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
descriptions: &diagnostics::registry::Registry)
-> Option<(Input, Option<PathBuf>)> {
self.0.no_input(matches, sopts, odir, ofile, descriptions)
}
fn late_callback(&mut self,
matches: &getopts::Matches,
sess: &Session,
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>)
-> Compilation {
self.0.late_callback(matches, sess, input, odir, ofile)
}
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
let mut control = self.0.build_controller(sess, matches);
let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
control.after_parse.callback = Box::new(move |state| {
{
let mut registry = rustc_plugin::registry::Registry::new(state.session, state.krate.as_ref().expect("at this compilation stage the krate must be parsed"));
registry.args_hidden = Some(Vec::new());
plugin_registrar(&mut registry);
let rustc_plugin::registry::Registry { early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, mir_passes, .. } = registry;
let sess = &state.session;
let mut ls = sess.lint_store.borrow_mut();
for pass in early_lint_passes {
ls.register_early_pass(Some(sess), true, pass);
}
for pass in late_lint_passes {
ls.register_late_pass(Some(sess), true, pass);
}
for (name, to) in lint_groups {
ls.register_group(Some(sess), true, name, to);
}
sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
sess.mir_passes.borrow_mut().extend(mir_passes);
sess.plugin_attributes.borrow_mut().extend(attributes);
}
old(state);
});
control
}
}
use std::path::Path;
pub fn main() {
use std::env;
if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
return;
}
let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps");
let sys_root = match (option_env!("MULTIRUST_HOME"), option_env!("MULTIRUST_TOOLCHAIN")) {
(Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
_ => option_env!("SYSROOT").expect("need to specify SYSROOT env var during clippy compilation or use multirust").to_owned(),
};
if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
let args = wrap_args(std::env::args().skip(2), dep_path, sys_root);
let path = std::env::current_exe().expect("current executable path invalid");
let run = std::process::Command::new("cargo")
.args(&args)
.env("RUSTC", path)
.spawn().expect("could not run cargo")
.wait().expect("failed to wait for cargo?")
.success();
assert!(run, "cargo rustc failed");
} else {
let args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
env::args().collect()
} else {
env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect()
};
rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new());
}
}
fn wrap_args<P, I>(old_args: I, dep_path: P, sysroot: String) -> Vec<String>
where P: AsRef<Path>, I: Iterator<Item=String> {
let mut args = vec!["rustc".to_owned()];
let mut found_dashes = false;
for arg in old_args {
found_dashes |= arg == "--";
args.push(arg);
}
if !found_dashes {
args.push("--".to_owned());
}
args.push("-L".to_owned());
args.push(dep_path.as_ref().to_string_lossy().into_owned());
args.push(String::from("--sysroot"));
args.push(sysroot);
args.push("-Zno-trans".to_owned());
args
}
#[macro_use]

View file

@ -1,9 +1,11 @@
#![feature(test)]
#![feature(test, plugin)]
#![plugin(clippy)]
#![deny(clippy, clippy_pedantic)]
extern crate compiletest_rs as compiletest;
extern crate test;
use std::env::var;
use std::env::{var, set_var};
use std::path::PathBuf;
use test::TestPaths;
@ -11,15 +13,14 @@ use test::TestPaths;
fn dogfood() {
let mut config = compiletest::default_config();
let cfg_mode = "run-pass".parse().ok().expect("Invalid mode");
let cfg_mode = "run-pass".parse().expect("Invalid mode");
let mut s = String::new();
s.push_str(" -L target/debug/");
s.push_str(" -L target/debug/deps");
s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy");
config.target_rustcflags = Some(s);
if let Ok(name) = var::<&str>("TESTNAME") {
let s : String = name.to_owned();
config.filter = Some(s)
if let Ok(name) = var("TESTNAME") {
config.filter = Some(name.to_owned())
}
config.mode = cfg_mode;
@ -29,5 +30,8 @@ fn dogfood() {
file: PathBuf::from("src/lib.rs"),
relative_dir: PathBuf::new(),
};
set_var("CLIPPY_DOGFOOD", "tastes like chicken");
compiletest::runtest::run(config, &paths);
}