Skip to content

Commit

Permalink
Merge pull request #681 from oli-obk/split
Browse files Browse the repository at this point in the history
cargo clippy
  • Loading branch information
Manishearth committed May 10, 2016
2 parents dc75836 + 654154d commit 855b292
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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`:

Expand All @@ -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:

Expand All @@ -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`:
Expand Down
144 changes: 139 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
16 changes: 10 additions & 6 deletions tests/dogfood.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
#![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;

#[test]
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;
Expand All @@ -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);
}

0 comments on commit 855b292

Please sign in to comment.