diff --git a/.travis.yml b/.travis.yml index b204bb0b2f5..c1b91fd75fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,8 @@ script: - cargo build --features debugging - cargo test --features debugging - SYSROOT=~/rust cargo install - - cargo clippy --lib -- -D clippy + - cargo clippy -- -D clippy + - cd clippy_lints && cargo clippy -- -D clippy && cd .. after_success: # only test regex_macros if it compiles diff --git a/Cargo.toml b/Cargo.toml index 672b9d7ef94..828857701d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,12 +32,12 @@ quine-mc_cluskey = "0.2.2" # begin automatic update clippy_lints = { version = "0.0.70", path = "clippy_lints" } # end automatic update +rustc-serialize = "0.3" [dev-dependencies] compiletest_rs = "0.1.0" lazy_static = "0.1.15" regex = "0.1.56" -rustc-serialize = "0.3" [features] debugging = [] diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index aa994cd7259..c309b7a63e2 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -21,6 +21,7 @@ semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" quine-mc_cluskey = "0.2.2" +rustc-serialize = "0.3" [features] debugging = [] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4a5c3a87c8c..944825e2bdc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -36,6 +36,8 @@ extern crate regex_syntax; // for finding minimal boolean expressions extern crate quine_mc_cluskey; +extern crate rustc_serialize; + extern crate rustc_plugin; extern crate rustc_const_eval; extern crate rustc_const_math; diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs new file mode 100644 index 00000000000..c6004864bf0 --- /dev/null +++ b/clippy_lints/src/utils/cargo.rs @@ -0,0 +1,75 @@ +use std::collections::HashMap; +use std::process::Command; +use std::str::{from_utf8, Utf8Error}; +use std::io; +use rustc_serialize::json; + +#[derive(RustcDecodable, Debug)] +pub struct Metadata { + pub packages: Vec, + resolve: Option<()>, + pub version: usize, +} + +#[derive(RustcDecodable, Debug)] +pub struct Package { + pub name: String, + pub version: String, + id: String, + source: Option<()>, + pub dependencies: Vec, + pub targets: Vec, + features: HashMap>, + manifest_path: String, +} + +#[derive(RustcDecodable, Debug)] +pub struct Dependency { + pub name: String, + source: Option, + pub req: String, + kind: Option, + optional: bool, + uses_default_features: bool, + features: Vec>, + target: Option<()>, +} + +#[allow(non_camel_case_types)] +#[derive(RustcDecodable, Debug)] +pub enum Kind { + dylib, + test, + bin, + lib, +} + +#[derive(RustcDecodable, Debug)] +pub struct Target { + pub name: String, + pub kind: Vec, + src_path: String, +} + +#[derive(Debug)] +pub enum Error { + Io(io::Error), + Utf8(Utf8Error), + Json(json::DecoderError), +} + +impl From for Error { + fn from(err: io::Error) -> Self { Error::Io(err) } +} +impl From for Error { + fn from(err: Utf8Error) -> Self { Error::Utf8(err) } +} +impl From for Error { + fn from(err: json::DecoderError) -> Self { Error::Json(err) } +} + +pub fn metadata() -> Result { + let output = Command::new("cargo").args(&["metadata", "--no-deps"]).output()?; + let stdout = from_utf8(&output.stdout)?; + Ok(json::decode(stdout)?) +} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index c1cbd7ffe93..986462b3723 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -23,6 +23,7 @@ pub mod conf; mod hir; pub mod paths; pub use self::hir::{SpanlessEq, SpanlessHash}; +pub mod cargo; pub type MethodArgs = HirVec>; diff --git a/src/main.rs b/src/main.rs index 970222e1076..3ad32a54058 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(slice_patterns)] extern crate rustc_driver; extern crate getopts; @@ -8,6 +9,7 @@ extern crate rustc; extern crate syntax; extern crate rustc_plugin; extern crate clippy_lints; +extern crate rustc_serialize; use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; use rustc::session::{config, Session}; @@ -16,6 +18,8 @@ use syntax::diagnostics; use std::path::PathBuf; use std::process::Command; +use clippy_lints::utils::cargo; + struct ClippyCompilerCalls(RustcDefaultCalls); impl std::default::Default for ClippyCompilerCalls { @@ -118,16 +122,18 @@ pub fn main() { }; 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 exit_status = std::process::Command::new("cargo") - .args(&args) - .env("RUSTC", path) - .spawn().expect("could not run cargo") - .wait().expect("failed to wait for cargo?"); - - if let Some(code) = exit_status.code() { - std::process::exit(code); + let mut metadata = cargo::metadata().expect("could not obtain cargo metadata"); + assert_eq!(metadata.version, 1); + for target in metadata.packages.remove(0).targets { + let args = std::env::args().skip(2); + assert_eq!(target.kind.len(), 1); + match &target.kind[..] { + [cargo::Kind::lib] | + [cargo::Kind::dylib] => process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root), + [cargo::Kind::bin] => process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root), + // don't process tests and other stuff + _ => {}, + } } } else { let args: Vec = if env::args().any(|s| s == "--sysroot") { @@ -145,7 +151,7 @@ pub fn main() { } } -fn wrap_args(old_args: I, dep_path: P, sysroot: String) -> Vec +fn process(old_args: I, dep_path: P, sysroot: &str) where P: AsRef, I: Iterator { let mut args = vec!["rustc".to_owned()]; @@ -161,7 +167,17 @@ fn wrap_args(old_args: I, dep_path: P, sysroot: String) -> Vec 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(sysroot.to_owned()); args.push("-Zno-trans".to_owned()); - args + + let path = std::env::current_exe().expect("current executable path invalid"); + let exit_status = std::process::Command::new("cargo") + .args(&args) + .env("RUSTC", path) + .spawn().expect("could not run cargo") + .wait().expect("failed to wait for cargo?"); + + if let Some(code) = exit_status.code() { + std::process::exit(code); + } } diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs new file mode 100644 index 00000000000..b2a2f416a8f --- /dev/null +++ b/tests/versioncheck.rs @@ -0,0 +1,16 @@ +extern crate clippy_lints; +use clippy_lints::utils::cargo; + +#[test] +fn check_that_clippy_lints_has_the_same_version_as_clippy() { + let clippy_meta = cargo::metadata().expect("could not obtain cargo metadata"); + std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); + let clippy_lints_meta = cargo::metadata().expect("could not obtain cargo metadata"); + assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); + for package in &clippy_meta.packages[0].dependencies { + if package.name == "clippy_lints" { + assert_eq!(clippy_lints_meta.packages[0].version, package.req[1..]); + return; + } + } +}