diff --git a/mk/tests.mk b/mk/tests.mk index 87cfed2426e..2e7b85f5728 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -242,13 +242,13 @@ cleantestlibs: .PHONY: tidy tidy: $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)) - $< $(S)src + $(TARGET_RPATH_VAR0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $< $(S)src $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)): \ $(TSREQ0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \ $(TLIB0_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.std \ $(call rwildcard,$(S)src/tools/tidy/src,*.rs) - $(STAGE0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) src/tools/tidy/src/main.rs \ + $(STAGE0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(S)src/tools/tidy/src/main.rs \ --out-dir $(@D) --crate-name tidy ###################################################################### diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index 626cf758631..45e0cb11010 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -323,8 +323,7 @@ impl<'a> Step<'a> { } Source::ToolLinkchecker { stage } | - Source::ToolTidy { stage } | - Source::ToolCargoTest { stage } => { + Source::ToolTidy { stage } => { vec![self.libstd(self.compiler(stage))] } Source::ToolErrorIndex { stage } | diff --git a/src/rustc/test_shim/lib.rs b/src/rustc/test_shim/lib.rs index a626c9440d8..d614d967e3b 100644 --- a/src/rustc/test_shim/lib.rs +++ b/src/rustc/test_shim/lib.rs @@ -9,3 +9,7 @@ // except according to those terms. // See comments in Cargo.toml for why this exists + +#![feature(test)] + +extern crate test; diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs new file mode 100644 index 00000000000..a170ecfdce0 --- /dev/null +++ b/src/tools/tidy/src/cargo.rs @@ -0,0 +1,95 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Tidy check to ensure that `[dependencies]` and `extern crate` are in sync. +//! +//! This tidy check ensures that all crates listed in the `[dependencies]` +//! section of a `Cargo.toml` are present in the corresponding `lib.rs` as +//! `extern crate` declarations. This should help us keep the DAG correctly +//! structured through various refactorings to prune out unnecessary edges. + +use std::io::prelude::*; +use std::fs::File; +use std::path::Path; + +pub fn check(path: &Path, bad: &mut bool) { + for entry in t!(path.read_dir()).map(|e| t!(e)) { + // Look for `Cargo.toml` with a sibling `src/lib.rs` or `lib.rs` + if entry.file_name().to_str() == Some("Cargo.toml") { + if path.join("src/lib.rs").is_file() { + verify(&entry.path(), &path.join("src/lib.rs"), bad) + } + if path.join("lib.rs").is_file() { + verify(&entry.path(), &path.join("lib.rs"), bad) + } + } else if t!(entry.file_type()).is_dir() { + check(&entry.path(), bad); + } + } +} + +// Verify that the dependencies in Cargo.toml at `tomlfile` are sync'd with the +// `extern crate` annotations in the lib.rs at `libfile`. +fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { + let mut toml = String::new(); + let mut librs = String::new(); + t!(t!(File::open(tomlfile)).read_to_string(&mut toml)); + t!(t!(File::open(libfile)).read_to_string(&mut librs)); + + if toml.contains("name = \"bootstrap\"") { + return + } + + // "Poor man's TOML parser", just assume we use one syntax for now + // + // We just look for: + // + // [dependencies] + // name = ... + // name2 = ... + // name3 = ... + // + // If we encounter a line starting with `[` then we assume it's the end of + // the dependency section and bail out. + let deps = match toml.find("[dependencies]") { + Some(i) => &toml[i+1..], + None => return, + }; + let mut lines = deps.lines().peekable(); + while let Some(line) = lines.next() { + if line.starts_with("[") { + break + } + + let mut parts = line.splitn(2, '='); + let krate = parts.next().unwrap().trim(); + if parts.next().is_none() { + continue + } + + // Don't worry about depending on core/std but not saying `extern crate + // core/std`, that's intentional. + if krate == "core" || krate == "std" { + continue + } + + // This is intentional, this dependency just makes the crate available + // for others later on. + if krate == "alloc_jemalloc" && toml.contains("name = \"std\"") { + continue + } + + if !librs.contains(&format!("extern crate {}", krate)) { + println!("{} doesn't have `extern crate {}`, but Cargo.toml \ + depends on it", libfile.display(), krate); + *bad = true; + } + } +} diff --git a/src/tools/tidy/src/errors.rs b/src/tools/tidy/src/errors.rs index 21ec9270429..41869288cc9 100644 --- a/src/tools/tidy/src/errors.rs +++ b/src/tools/tidy/src/errors.rs @@ -71,8 +71,7 @@ pub fn check(path: &Path, bad: &mut bool) { }); let mut max = 0; - println!("* {} error codes", map.len()); - for (code, entries) in map { + for (&code, entries) in map.iter() { if code > max { max = code; } @@ -81,10 +80,14 @@ pub fn check(path: &Path, bad: &mut bool) { } println!("duplicate error code: {}", code); - for (file, line_num, line) in entries { + for &(ref file, line_num, ref line) in entries.iter() { println!("{}:{}: {}", file.display(), line_num, line); } *bad = true; } - println!("* highest error code: E{:04}", max); + + if !*bad { + println!("* {} error codes", map.len()); + println!("* highest error code: E{:04}", max); + } } diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index c665b6e662f..991cf201d44 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -100,6 +100,10 @@ pub fn check(path: &Path, bad: &mut bool) { } }); + if *bad { + return + } + let mut lines = Vec::new(); for feature in features { lines.push(format!("{:<32} {:<8} {:<12} {:<8}", diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index d8acf3250df..85b9c345e19 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -29,6 +29,7 @@ mod bins; mod style; mod errors; mod features; +mod cargo; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -38,6 +39,7 @@ fn main() { bins::check(&path, &mut bad); style::check(&path, &mut bad); errors::check(&path, &mut bad); + cargo::check(&path, &mut bad); features::check(&path, &mut bad); if bad {