Close the front door for clippy but open the back

This commit is contained in:
Jane Lusby 2019-10-22 07:53:51 -07:00
parent 2bdc87972c
commit b0351e4d87
19 changed files with 394 additions and 301 deletions

View File

@ -1679,6 +1679,7 @@ thread_local!(
pub static RUSTC: Rustc = Rustc::new(
PathBuf::from("rustc"),
None,
None,
Path::new("should be path to rustup rustc, but we don't care in tests"),
None,
).unwrap()

View File

@ -264,3 +264,22 @@ pub fn sysroot() -> String {
let sysroot = String::from_utf8(output.stdout).unwrap();
sysroot.trim().to_string()
}
#[cfg(unix)]
pub fn echo_wrapper() -> std::io::Result<std::path::PathBuf> {
use std::os::unix::fs::PermissionsExt;
let wrapper_path = root().join("rustc-echo-wrapper");
std::fs::write(
&wrapper_path,
r#"#! /bin/bash
echo "WRAPPER CALLED: $*"
"$@""#,
)?;
let mut perms = std::fs::metadata(&wrapper_path)?.permissions();
perms.set_mode(0o755);
std::fs::set_permissions(&wrapper_path, perms)?;
Ok(wrapper_path)
}

View File

@ -1,85 +0,0 @@
use crate::command_prelude::*;
use cargo::ops;
use cargo::util;
pub fn cli() -> App {
subcommand("clippy-preview")
.about("Checks a package to catch common mistakes and improve your Rust code.")
.arg(Arg::with_name("args").multiple(true))
.arg_package_spec(
"Package(s) to check",
"Check all packages in the workspace",
"Exclude packages from the check",
)
.arg_jobs()
.arg_targets_all(
"Check only this package's library",
"Check only the specified binary",
"Check all binaries",
"Check only the specified example",
"Check all examples",
"Check only the specified test target",
"Check all tests",
"Check only the specified bench target",
"Check all benches",
"Check all targets",
)
.arg_release("Check artifacts in release mode, with optimizations")
.arg_profile("Check artifacts with the specified profile")
.arg_features()
.arg_target_triple("Check for the target triple")
.arg_target_dir()
.arg_manifest_path()
.arg_message_format()
.after_help(
"\
If the `--package` argument is given, then SPEC is a package ID specification
which indicates which package should be built. If it is not given, then the
current package is built. For more information on SPEC and its format, see the
`cargo help pkgid` command.
All packages in the workspace are checked if the `--workspace` flag is supplied. The
`--workspace` flag is automatically assumed for a virtual manifest.
Note that `--exclude` has to be specified in conjunction with the `--workspace` flag.
To allow or deny a lint from the command line you can use `cargo clippy --`
with:
-W --warn OPT Set lint warnings
-A --allow OPT Set lint allowed
-D --deny OPT Set lint denied
-F --forbid OPT Set lint forbidden
You can use tool lints to allow or deny lints from your code, eg.:
#[allow(clippy::needless_lifetimes)]
",
)
}
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;
let mode = CompileMode::Check { test: false };
let mut compile_opts =
args.compile_options(config, mode, Some(&ws), ProfileChecking::Checked)?;
if !config.cli_unstable().unstable_options {
return Err(anyhow::format_err!(
"`clippy-preview` is unstable, pass `-Z unstable-options` to enable it"
)
.into());
}
let mut wrapper = util::process(util::config::clippy_driver());
if let Some(clippy_args) = args.values_of("args") {
wrapper.args(&clippy_args.collect::<Vec<_>>());
}
compile_opts.build_config.primary_unit_rustc = Some(wrapper);
ops::compile(&ws, &compile_opts)?;
Ok(())
}

View File

@ -72,15 +72,6 @@ pub fn cli() -> App {
.long("allow-staged")
.help("Fix code even if the working directory has staged changes"),
)
.arg(
Arg::with_name("clippy")
.long("clippy")
.help("Get fix suggestions from clippy instead of rustc")
.hidden(true)
.multiple(true)
.min_values(0)
.number_of_values(1),
)
.after_help(
"\
This Cargo subcommand will automatically take rustc's suggestions from
@ -134,21 +125,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
// code as we can.
let mut opts = args.compile_options(config, mode, Some(&ws), ProfileChecking::Unchecked)?;
let use_clippy = args.is_present("clippy");
let clippy_args = args
.value_of("clippy")
.map(|s| s.split(' ').map(|s| s.to_string()).collect())
.or_else(|| Some(vec![]))
.filter(|_| use_clippy);
if use_clippy && !config.cli_unstable().unstable_options {
return Err(anyhow::format_err!(
"`cargo fix --clippy` is unstable, pass `-Z unstable-options` to enable it"
)
.into());
}
if let CompileFilter::Default { .. } = opts.filter {
opts.filter = CompileFilter::Only {
all_targets: true,
@ -171,7 +147,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
allow_no_vcs: args.is_present("allow-no-vcs"),
allow_staged: args.is_present("allow-staged"),
broken_code: args.is_present("broken-code"),
clippy_args,
},
)?;
Ok(())

View File

@ -6,7 +6,6 @@ pub fn builtin() -> Vec<App> {
build::cli(),
check::cli(),
clean::cli(),
clippy::cli(),
doc::cli(),
fetch::cli(),
fix::cli(),
@ -43,7 +42,6 @@ pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches<'_>) -> Cli
"build" => build::exec,
"check" => check::exec,
"clean" => clean::exec,
"clippy-preview" => clippy::exec,
"doc" => doc::exec,
"fetch" => fetch::exec,
"fix" => fix::exec,
@ -80,7 +78,6 @@ pub mod bench;
pub mod build;
pub mod check;
pub mod clean;
pub mod clippy;
pub mod doc;
pub mod fetch;
pub mod fix;

View File

@ -22,7 +22,7 @@ pub struct BuildConfig {
pub force_rebuild: bool,
/// Output a build plan to stdout instead of actually compiling.
pub build_plan: bool,
/// An optional override of the rustc path for primary units only
/// An optional override of the rustc process for primary units
pub primary_unit_rustc: Option<ProcessBuilder>,
pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
}

View File

@ -73,8 +73,14 @@ pub struct Compilation<'cfg> {
pub target: String,
config: &'cfg Config,
/// Rustc process to be used by default
rustc_process: ProcessBuilder,
primary_unit_rustc_process: Option<ProcessBuilder>,
/// Rustc process to be used for workspace crates instead of rustc_process
rustc_workspace_wrapper_process: ProcessBuilder,
/// Optional rustc process to be used for primary crates instead of either rustc_process or
/// rustc_workspace_wrapper_process
primary_rustc_process: Option<ProcessBuilder>,
target_runner: Option<(PathBuf, Vec<String>)>,
}
@ -85,13 +91,14 @@ impl<'cfg> Compilation<'cfg> {
default_kind: CompileKind,
) -> CargoResult<Compilation<'cfg>> {
let mut rustc = bcx.rustc().process();
let mut primary_unit_rustc_process = bcx.build_config.primary_unit_rustc.clone();
let mut primary_rustc_process = bcx.build_config.primary_unit_rustc.clone();
let mut rustc_workspace_wrapper_process = bcx.rustc().workspace_process();
if bcx.config.extra_verbose() {
rustc.display_env_vars();
rustc_workspace_wrapper_process.display_env_vars();
if let Some(rustc) = primary_unit_rustc_process.as_mut() {
if let Some(rustc) = primary_rustc_process.as_mut() {
rustc.display_env_vars();
}
}
@ -120,7 +127,8 @@ impl<'cfg> Compilation<'cfg> {
rustdocflags: HashMap::new(),
config: bcx.config,
rustc_process: rustc,
primary_unit_rustc_process,
rustc_workspace_wrapper_process,
primary_rustc_process,
host: bcx.host_triple().to_string(),
target: bcx.target_data.short_name(&default_kind).to_string(),
target_runner: target_runner(bcx, default_kind)?,
@ -128,11 +136,16 @@ impl<'cfg> Compilation<'cfg> {
}
/// See `process`.
pub fn rustc_process(&self, pkg: &Package, is_primary: bool) -> CargoResult<ProcessBuilder> {
let rustc = if is_primary {
self.primary_unit_rustc_process
.clone()
.unwrap_or_else(|| self.rustc_process.clone())
pub fn rustc_process(
&self,
pkg: &Package,
is_primary: bool,
is_workspace: bool,
) -> CargoResult<ProcessBuilder> {
let rustc = if is_primary && self.primary_rustc_process.is_some() {
self.primary_rustc_process.clone().unwrap()
} else if is_workspace {
self.rustc_workspace_wrapper_process.clone()
} else {
self.rustc_process.clone()
};

View File

@ -616,11 +616,11 @@ fn compute_metadata<'a, 'cfg>(
bcx.rustc().verbose_version.hash(&mut hasher);
if cx.is_primary_package(unit) {
if cx.bcx.ws.is_member(unit.pkg) {
// This is primarily here for clippy. This ensures that the clippy
// artifacts are separate from the `check` ones.
if let Some(proc) = &cx.bcx.build_config.primary_unit_rustc {
proc.get_program().hash(&mut hasher);
if let Some(path) = &cx.bcx.rustc().workspace_wrapper {
path.hash(&mut hasher);
}
}

View File

@ -1100,22 +1100,12 @@ fn calculate_normal<'a, 'cfg>(
// Fill out a bunch more information that we'll be tracking typically
// hashed to take up less space on disk as we just need to know when things
// change.
let mut extra_flags = if unit.mode.is_doc() {
let extra_flags = if unit.mode.is_doc() {
cx.bcx.rustdocflags_args(unit)
} else {
cx.bcx.rustflags_args(unit)
}
.to_vec();
if cx.is_primary_package(unit) {
// This is primarily here for clippy arguments.
if let Some(proc) = &cx.bcx.build_config.primary_unit_rustc {
let args = proc
.get_args()
.iter()
.map(|s| s.to_string_lossy().to_string());
extra_flags.extend(args);
}
}
let profile_hash = util::hash_u64((&unit.profile, unit.mode, cx.bcx.extra_args_for(unit)));
// Include metadata since it is exposed as environment variables.

View File

@ -538,8 +538,11 @@ fn prepare_rustc<'a, 'cfg>(
unit: &Unit<'a>,
) -> CargoResult<ProcessBuilder> {
let is_primary = cx.is_primary_package(unit);
let is_workspace = cx.bcx.ws.is_member(unit.pkg);
let mut base = cx.compilation.rustc_process(unit.pkg, is_primary)?;
let mut base = cx
.compilation
.rustc_process(unit.pkg, is_primary, is_workspace)?;
if cx.bcx.config.cli_unstable().jobserver_per_rustc {
let client = cx.new_jobserver()?;
base.inherit_jobserver(&client);

View File

@ -53,9 +53,10 @@ use rustfix::{self, CodeFix};
use crate::core::Workspace;
use crate::ops::{self, CompileOptions};
use crate::util;
use crate::util::diagnostic_server::{Message, RustfixDiagnosticServer};
use crate::util::errors::CargoResult;
use crate::util::{self, paths};
use crate::util::ProcessBuilder;
use crate::util::{existing_vcs_repo, LockServer, LockServerClient};
const FIX_ENV: &str = "__CARGO_FIX_PLZ";
@ -63,7 +64,6 @@ const BROKEN_CODE_ENV: &str = "__CARGO_FIX_BROKEN_CODE";
const PREPARE_FOR_ENV: &str = "__CARGO_FIX_PREPARE_FOR";
const EDITION_ENV: &str = "__CARGO_FIX_EDITION";
const IDIOMS_ENV: &str = "__CARGO_FIX_IDIOMS";
const CLIPPY_FIX_ARGS: &str = "__CARGO_FIX_CLIPPY_ARGS";
pub struct FixOptions<'a> {
pub edition: bool,
@ -74,7 +74,6 @@ pub struct FixOptions<'a> {
pub allow_no_vcs: bool,
pub allow_staged: bool,
pub broken_code: bool,
pub clippy_args: Option<Vec<String>>,
}
pub fn fix(ws: &Workspace<'_>, opts: &mut FixOptions<'_>) -> CargoResult<()> {
@ -101,19 +100,6 @@ pub fn fix(ws: &Workspace<'_>, opts: &mut FixOptions<'_>) -> CargoResult<()> {
wrapper.env(IDIOMS_ENV, "1");
}
if opts.clippy_args.is_some() {
if let Err(e) = util::process("clippy-driver").arg("-V").exec_with_output() {
eprintln!("Warning: clippy-driver not found: {:?}", e);
}
let clippy_args = opts
.clippy_args
.as_ref()
.map_or_else(String::new, |args| serde_json::to_string(&args).unwrap());
wrapper.env(CLIPPY_FIX_ARGS, clippy_args);
}
*opts
.compile_opts
.build_config
@ -222,12 +208,17 @@ pub fn fix_maybe_exec_rustc() -> CargoResult<bool> {
let args = FixArgs::get();
trace!("cargo-fix as rustc got file {:?}", args.file);
let rustc = args.rustc.as_ref().expect("fix wrapper rustc was not set");
let workspace_rustc = std::env::var("RUSTC_WORKSPACE_WRAPPER")
.map(PathBuf::from)
.ok();
let rustc = util::process(rustc).wrapped(workspace_rustc.as_ref());
let mut fixes = FixedCrate::default();
if let Some(path) = &args.file {
trace!("start rustfixing {:?}", path);
fixes = rustfix_crate(&lock_addr, rustc.as_ref(), path, &args)?;
fixes = rustfix_crate(&lock_addr, &rustc, path, &args)?;
}
// Ok now we have our final goal of testing out the changes that we applied.
@ -239,7 +230,7 @@ pub fn fix_maybe_exec_rustc() -> CargoResult<bool> {
// new rustc, and otherwise we capture the output to hide it in the scenario
// that we have to back it all out.
if !fixes.files.is_empty() {
let mut cmd = Command::new(&rustc);
let mut cmd = rustc.build_command();
args.apply(&mut cmd);
cmd.arg("--error-format=json");
let output = cmd.output().context("failed to spawn rustc")?;
@ -279,7 +270,7 @@ pub fn fix_maybe_exec_rustc() -> CargoResult<bool> {
// - If the fix failed, show the original warnings and suggestions.
// - If `--broken-code`, show the error messages.
// - If the fix succeeded, show any remaining warnings.
let mut cmd = Command::new(&rustc);
let mut cmd = rustc.build_command();
args.apply(&mut cmd);
for arg in args.format_args {
// Add any json/error format arguments that Cargo wants. This allows
@ -302,7 +293,7 @@ struct FixedFile {
fn rustfix_crate(
lock_addr: &str,
rustc: &Path,
rustc: &ProcessBuilder,
filename: &Path,
args: &FixArgs,
) -> Result<FixedCrate, Error> {
@ -402,7 +393,7 @@ fn rustfix_crate(
/// and any errors encountered while fixing files.
fn rustfix_and_fix(
fixes: &mut FixedCrate,
rustc: &Path,
rustc: &ProcessBuilder,
filename: &Path,
args: &FixArgs,
) -> Result<(), Error> {
@ -410,12 +401,15 @@ fn rustfix_and_fix(
// TODO: implement a way to specify this.
let only = HashSet::new();
let mut cmd = Command::new(rustc);
let mut cmd = rustc.build_command();
cmd.arg("--error-format=json");
args.apply(&mut cmd);
let output = cmd
.output()
.with_context(|| format!("failed to execute `{}`", rustc.display()))?;
let output = cmd.output().with_context(|| {
format!(
"failed to execute `{}`",
rustc.get_program().to_string_lossy()
)
})?;
// If rustc didn't succeed for whatever reasons then we're very likely to be
// looking at otherwise broken code. Let's not make things accidentally
@ -491,7 +485,7 @@ fn rustfix_and_fix(
// Attempt to read the source code for this file. If this fails then
// that'd be pretty surprising, so log a message and otherwise keep
// going.
let code = match paths::read(file.as_ref()) {
let code = match util::paths::read(file.as_ref()) {
Ok(s) => s,
Err(e) => {
warn!("failed to read `{}`: {}", file, e);
@ -591,7 +585,6 @@ struct FixArgs {
enabled_edition: Option<String>,
other: Vec<OsString>,
rustc: Option<PathBuf>,
clippy_args: Vec<String>,
format_args: Vec<String>,
}
@ -611,12 +604,7 @@ impl FixArgs {
fn get() -> FixArgs {
let mut ret = FixArgs::default();
if let Ok(clippy_args) = env::var(CLIPPY_FIX_ARGS) {
ret.clippy_args = serde_json::from_str(&clippy_args).unwrap();
ret.rustc = Some(util::config::clippy_driver());
} else {
ret.rustc = env::args_os().nth(1).map(PathBuf::from);
}
ret.rustc = env::args_os().nth(1).map(PathBuf::from);
for arg in env::args_os().skip(2) {
let path = PathBuf::from(arg);
@ -654,10 +642,6 @@ impl FixArgs {
cmd.arg(path);
}
if !self.clippy_args.is_empty() {
cmd.args(&self.clippy_args);
}
cmd.args(&self.other).arg("--cap-lints=warn");
if let Some(edition) = &self.enabled_edition {
cmd.arg("--edition").arg(edition);

View File

@ -314,9 +314,19 @@ impl Config {
.into_path_unlocked()
});
let wrapper = self.maybe_get_tool("rustc_wrapper", &self.build_config()?.rustc_wrapper);
let rustc_workspace_wrapper = self.maybe_get_tool(
"rustc_workspace_wrapper",
&self.build_config()?.rustc_workspace_wrapper,
);
if !self.cli_unstable().unstable_options && rustc_workspace_wrapper.is_some() {
bail!("Usage of `RUSTC_WORKSPACE_WRAPPER` requires `-Z unstable-options`")
}
Rustc::new(
self.get_tool("rustc", &self.build_config()?.rustc),
wrapper,
rustc_workspace_wrapper,
&self
.home()
.join("bin")
@ -1645,15 +1655,6 @@ impl Drop for PackageCacheLock<'_> {
}
}
/// returns path to clippy-driver binary
///
/// Allows override of the path via `CARGO_CLIPPY_DRIVER` env variable
pub fn clippy_driver() -> PathBuf {
env::var("CARGO_CLIPPY_DRIVER")
.unwrap_or_else(|_| "clippy-driver".into())
.into()
}
#[derive(Debug, Default, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub struct CargoHttpConfig {
@ -1714,6 +1715,7 @@ pub struct CargoBuildConfig {
pub rustflags: Option<StringList>,
pub rustdocflags: Option<StringList>,
pub rustc_wrapper: Option<PathBuf>,
pub rustc_workspace_wrapper: Option<PathBuf>,
pub rustc: Option<PathBuf>,
pub rustdoc: Option<PathBuf>,
pub out_dir: Option<ConfigRelativePath>,

View File

@ -6,6 +6,7 @@ use std::collections::BTreeMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::iter::once;
use std::path::Path;
use std::process::{Command, Output, Stdio};
@ -326,6 +327,37 @@ impl ProcessBuilder {
}
command
}
/// Wraps an existing command with the provided wrapper, if it is present and valid.
///
/// # Examples
///
/// ```rust
/// use cargo::util::{ProcessBuilder, process};
/// // Running this would execute `rustc`
/// let cmd: ProcessBuilder = process("rustc");
///
/// // Running this will execute `sccache rustc`
/// let cmd = cmd.wrapped(Some("sccache"));
/// ```
pub fn wrapped(mut self, wrapper: Option<impl AsRef<OsStr>>) -> Self {
let wrapper = if let Some(wrapper) = wrapper.as_ref() {
wrapper.as_ref()
} else {
return self;
};
if wrapper.is_empty() {
return self;
}
let args = once(self.program).chain(self.args.into_iter()).collect();
self.program = wrapper.to_os_string();
self.args = args;
self
}
}
/// A helper function to create a `ProcessBuilder`.

View File

@ -20,7 +20,9 @@ pub struct Rustc {
pub path: PathBuf,
/// An optional program that will be passed the path of the rust exe as its first argument, and
/// rustc args following this.
pub wrapper: Option<ProcessBuilder>,
pub wrapper: Option<PathBuf>,
/// An optional wrapper to be used in addition to `rustc.wrapper` for workspace crates
pub workspace_wrapper: Option<PathBuf>,
/// Verbose version information (the output of `rustc -vV`)
pub verbose_version: String,
/// The host triple (arch-platform-OS), this comes from verbose_version.
@ -37,6 +39,7 @@ impl Rustc {
pub fn new(
path: PathBuf,
wrapper: Option<PathBuf>,
workspace_wrapper: Option<PathBuf>,
rustup_rustc: &Path,
cache_location: Option<PathBuf>,
) -> CargoResult<Rustc> {
@ -64,7 +67,8 @@ impl Rustc {
Ok(Rustc {
path,
wrapper: wrapper.map(util::process),
wrapper,
workspace_wrapper,
verbose_version,
host,
cache: Mutex::new(cache),
@ -72,20 +76,15 @@ impl Rustc {
}
/// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`.
pub fn process_with(&self, path: impl AsRef<Path>) -> ProcessBuilder {
match self.wrapper {
Some(ref wrapper) if !wrapper.get_program().is_empty() => {
let mut cmd = wrapper.clone();
cmd.arg(path.as_ref());
cmd
}
_ => util::process(path.as_ref()),
}
pub fn process(&self) -> ProcessBuilder {
util::process(self.path.as_path()).wrapped(self.wrapper.as_ref())
}
/// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`.
pub fn process(&self) -> ProcessBuilder {
self.process_with(&self.path)
pub fn workspace_process(&self) -> ProcessBuilder {
util::process(self.path.as_path())
.wrapped(self.workspace_wrapper.as_ref())
.wrapped(self.wrapper.as_ref())
}
pub fn process_no_wrapper(&self) -> ProcessBuilder {
@ -95,10 +94,6 @@ impl Rustc {
pub fn cached_output(&self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
self.cache.lock().unwrap().cached_output(cmd)
}
pub fn set_wrapper(&mut self, wrapper: ProcessBuilder) {
self.wrapper = Some(wrapper);
}
}
/// It is a well known fact that `rustc` is not the fastest compiler in the

View File

@ -3700,6 +3700,42 @@ fn rustc_wrapper_from_path() {
.run();
}
#[cargo_test]
// NOTE: we don't have `/usr/bin/env` on Windows.
#[cfg(not(windows))]
fn rustc_workspace_wrapper() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", "/usr/bin/env")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[RUNNING] `/usr/bin/env rustc --crate-name foo [..]")
.run();
}
#[cargo_test]
#[cfg(not(windows))]
fn rustc_workspace_wrapper_relative() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", "./sccache")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains("[..]/foo/./sccache rustc[..]")
.run();
}
#[cargo_test]
#[cfg(not(windows))]
fn rustc_workspace_wrapper_from_path() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", "wannabe_sccache")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains("[..]`wannabe_sccache rustc [..]")
.run();
}
#[cargo_test]
fn cdylib_not_lifted() {
let p = project()

View File

@ -1,8 +1,7 @@
//! Tests for caching compiler diagnostics.
use cargo_test_support::{
basic_manifest, command_is_available, is_coarse_mtime, process, project, registry::Package,
sleep_ms,
basic_manifest, is_coarse_mtime, process, project, registry::Package, sleep_ms,
};
use std::path::Path;
@ -274,56 +273,6 @@ fn fix() {
assert_eq!(p.read_file("src/lib.rs"), "pub fn r#try() {}");
}
#[cargo_test]
fn clippy() {
if !command_is_available("clippy-driver") {
return;
}
// Caching clippy output.
// This is just a random clippy lint (assertions_on_constants) that
// hopefully won't change much in the future.
let p = project()
.file(
"src/lib.rs",
"pub fn f() { assert!(true); }\n\
fn unused_func() {}",
)
.build();
p.cargo("clippy-preview -Zunstable-options -v")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[RUNNING] `clippy[..]")
.with_stderr_contains("[..]assert!(true)[..]")
.run();
// `check` should be separate from clippy.
p.cargo("check -v")
.with_stderr_contains(
"\
[CHECKING] foo [..]
[RUNNING] `rustc[..]
[WARNING] [..]unused_func[..]
",
)
.with_stderr_does_not_contain("[..]assert!(true)[..]")
.run();
// Again, reading from the cache.
p.cargo("clippy-preview -Zunstable-options -v")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[FRESH] foo [..]")
.with_stderr_contains("[..]assert!(true)[..]")
.run();
// And `check` should also be fresh, reading from cache.
p.cargo("check -v")
.with_stderr_contains("[FRESH] foo [..]")
.with_stderr_contains("[WARNING] [..]unused_func[..]")
.with_stderr_does_not_contain("[..]assert!(true)[..]")
.run();
}
#[cargo_test]
fn very_verbose() {
// Handle cap-lints in dependencies.
@ -496,3 +445,50 @@ fn caching_large_output() {
))
.run();
}
#[cargo_test]
#[cfg(unix)]
fn rustc_workspace_wrapper() {
use cargo_test_support::paths;
let p = project()
.file(
"src/lib.rs",
"pub fn f() { assert!(true); }\n\
fn unused_func() {}",
)
.build();
p.cargo("check -Zunstable-options -v")
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
.masquerade_as_nightly_cargo()
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
.run();
// Check without a wrapper should rebuild
p.cargo("check -v")
.with_stderr_contains(
"\
[CHECKING] foo [..]
[RUNNING] `rustc[..]
[WARNING] [..]unused_func[..]
",
)
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
.run();
// Again, reading from the cache.
p.cargo("check -Zunstable-options -v")
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
.masquerade_as_nightly_cargo()
.with_stderr_contains("[FRESH] foo [..]")
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
.run();
// And `check` should also be fresh, reading from cache.
p.cargo("check -v")
.with_stderr_contains("[FRESH] foo [..]")
.with_stderr_contains("[WARNING] [..]unused_func[..]")
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
.run();
}

View File

@ -752,6 +752,15 @@ fn does_not_use_empty_rustc_wrapper() {
p.cargo("check").env("RUSTC_WRAPPER", "").run();
}
#[cargo_test]
fn does_not_use_empty_rustc_workspace_wrapper() {
let p = project().file("src/lib.rs", "").build();
p.cargo("check -Zunstable-options")
.masquerade_as_nightly_cargo()
.env("RUSTC_WORKSPACE_WRAPPER", "")
.run();
}
#[cargo_test]
fn error_from_deep_recursion() -> Result<(), fmt::Error> {
let mut big_macro = String::new();
@ -772,3 +781,128 @@ fn error_from_deep_recursion() -> Result<(), fmt::Error> {
Ok(())
}
#[cargo_test]
#[cfg(unix)]
fn rustc_workspace_wrapper_affects_all_workspace_members() {
use cargo_test_support::paths;
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar", "baz"]
"#,
)
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
p.cargo("check -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
.masquerade_as_nightly_cargo()
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name baz [..]")
.run();
}
#[cargo_test]
#[cfg(unix)]
fn rustc_workspace_wrapper_includes_path_deps() {
use cargo_test_support::paths;
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
[dependencies]
baz = { path = "baz" }
"#,
)
.file("src/lib.rs", "")
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
p.cargo("check --workspace -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
.masquerade_as_nightly_cargo()
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name foo [..]")
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name baz [..]")
.run();
}
#[cargo_test]
#[cfg(unix)]
fn rustc_workspace_wrapper_respects_primary_units() {
use cargo_test_support::paths;
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar", "baz"]
"#,
)
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
p.cargo("check -p bar -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
.masquerade_as_nightly_cargo()
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name baz [..]")
.run();
}
#[cargo_test]
#[cfg(unix)]
fn rustc_workspace_wrapper_excludes_published_deps() {
use cargo_test_support::paths;
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
[dependencies]
baz = "1.0.0"
"#,
)
.file("src/lib.rs", "")
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
.build();
Package::new("baz", "1.0.0").publish();
p.cargo("check --workspace -v -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
.masquerade_as_nightly_cargo()
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name foo [..]")
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
.with_stderr_contains("[CHECKING] baz [..]")
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name baz [..]")
.run();
}

View File

@ -3,7 +3,9 @@
use std::fs::File;
use cargo_test_support::git;
use cargo_test_support::{basic_manifest, command_is_available, project};
#[cfg(unix)]
use cargo_test_support::paths;
use cargo_test_support::{basic_manifest, project};
use std::io::Write;
@ -1068,11 +1070,8 @@ fn doesnt_rebuild_dependencies() {
}
#[cargo_test]
#[cfg(unix)]
fn does_not_crash_with_rustc_wrapper() {
// We don't have /usr/bin/env on Windows.
if cfg!(windows) {
return;
}
let p = project()
.file(
"Cargo.toml",
@ -1090,6 +1089,50 @@ fn does_not_crash_with_rustc_wrapper() {
.run();
}
#[cargo_test]
#[cfg(unix)]
fn does_not_crash_with_rustc_workspace_wrapper() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("fix --allow-no-vcs --verbose -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", "/usr/bin/env")
.masquerade_as_nightly_cargo()
.run();
}
#[cargo_test]
#[cfg(unix)]
fn uses_workspace_wrapper_and_primary_wrapper_override() {
// We don't have /usr/bin/env on Windows.
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("fix --allow-no-vcs --verbose -Zunstable-options")
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
.masquerade_as_nightly_cargo()
.with_stdout_contains("WRAPPER CALLED: rustc src/lib.rs --crate-name foo [..]")
.run();
}
#[cargo_test]
fn only_warn_for_relevant_crates() {
let p = project()
@ -1251,47 +1294,6 @@ fn fix_in_existing_repo_weird_ignore() {
p.cargo("fix").cwd("src").run();
}
#[cargo_test]
fn fix_with_clippy() {
if !command_is_available("clippy-driver") {
return;
}
let p = project()
.file(
"src/lib.rs",
"
pub fn foo() {
let mut v = Vec::<String>::new();
let _ = v.iter_mut().filter(|&ref a| a.is_empty());
}
",
)
.build();
let stderr = "\
[CHECKING] foo v0.0.1 ([..])
[FIXING] src/lib.rs (1 fix)
[FINISHED] [..]
";
p.cargo("fix -Zunstable-options --clippy --allow-no-vcs")
.masquerade_as_nightly_cargo()
.with_stderr(stderr)
.with_stdout("")
.run();
assert_eq!(
p.read_file("src/lib.rs"),
"
pub fn foo() {
let mut v = Vec::<String>::new();
let _ = v.iter_mut().filter(|a| a.is_empty());
}
"
);
}
#[cargo_test]
fn fix_color_message() {
// Check that color appears in diagnostics.

View File

@ -28,7 +28,6 @@ mod cargo_targets;
mod cfg;
mod check;
mod clean;
mod clippy;
mod collisions;
mod concurrent;
mod config;