Auto merge of #9707 - Alexendoo:file-depinfo, r=flip1995

Track `clippy.toml` and `Cargo.toml` in `file_depinfo`

Causes cargo to re-run clippy when those paths are modified

Also tracks the path to `clippy-driver` in debug mode to remove the workarounds in `cargo dev lint` and `lintcheck` (cc `@matthiaskrgr)`

changelog: Automatically re-run Clippy if `Cargo.toml` or `clippy.toml` are modified

Fixes #2130
Fixes #8512

r? `@flip1995`
This commit is contained in:
bors 2022-10-25 12:08:46 +00:00
commit 5e298706f4
6 changed files with 47 additions and 59 deletions

View File

@ -10,7 +10,6 @@ indoc = "1.0"
itertools = "0.10.1"
opener = "0.5"
shell-escape = "0.1"
tempfile = "3.2"
walkdir = "2.3"
[features]

View File

@ -36,20 +36,12 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
} else {
exit_if_err(Command::new("cargo").arg("build").status());
// Run in a tempdir as changes to clippy do not retrigger linting
let target = tempfile::Builder::new()
.prefix("clippy")
.tempdir()
.expect("failed to create tempdir");
let status = Command::new(cargo_clippy_path())
.arg("clippy")
.args(args)
.current_dir(path)
.env("CARGO_TARGET_DIR", target.as_ref())
.status();
target.close().expect("failed to remove tempdir");
exit_if_err(status);
}
}

View File

@ -49,6 +49,9 @@
#[macro_use]
extern crate declare_clippy_lint;
use std::io;
use std::path::PathBuf;
use clippy_utils::parse_msrv;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{Lint, LintId};
@ -304,8 +307,8 @@
mod zero_sized_map_values;
// end lints modules, do not remove this comment, its used in `update_lints`
pub use crate::utils::conf::Conf;
use crate::utils::conf::{format_error, TryConf};
pub use crate::utils::conf::{lookup_conf_file, Conf};
/// Register all pre expansion lints
///
@ -362,8 +365,8 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
}
#[doc(hidden)]
pub fn read_conf(sess: &Session) -> Conf {
let file_name = match utils::conf::lookup_conf_file() {
pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
let file_name = match path {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
Err(error) => {
@ -373,7 +376,7 @@ pub fn read_conf(sess: &Session) -> Conf {
},
};
let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
let TryConf { conf, errors, warnings } = utils::conf::read(file_name);
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
sess.err(format!(

View File

@ -401,6 +401,10 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
}
/// Search for the configuration file.
///
/// # Errors
///
/// Returns any unexpected filesystem error encountered when searching for the config file
pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
/// Possible filename to search for.
const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

View File

@ -544,34 +544,6 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
(stats_string, counter)
}
/// check if the latest modification of the logfile is older than the modification date of the
/// clippy binary, if this is true, we should clean the lintchec shared target directory and recheck
fn lintcheck_needs_rerun(lintcheck_logs_path: &Path, paths: [&Path; 2]) -> bool {
if !lintcheck_logs_path.exists() {
return true;
}
let clippy_modified: std::time::SystemTime = {
let [cargo, driver] = paths.map(|p| {
std::fs::metadata(p)
.expect("failed to get metadata of file")
.modified()
.expect("failed to get modification date")
});
// the oldest modification of either of the binaries
std::cmp::max(cargo, driver)
};
let logs_modified: std::time::SystemTime = std::fs::metadata(lintcheck_logs_path)
.expect("failed to get metadata of file")
.modified()
.expect("failed to get modification date");
// time is represented in seconds since X
// logs_modified 2 and clippy_modified 5 means clippy binary is older and we need to recheck
logs_modified < clippy_modified
}
#[allow(clippy::too_many_lines)]
fn main() {
// We're being executed as a `RUSTC_WRAPPER` as part of `--recursive`
@ -594,23 +566,6 @@ fn main() {
let cargo_clippy_path = fs::canonicalize(format!("target/debug/cargo-clippy{EXE_SUFFIX}")).unwrap();
let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap();
// if the clippy bin is newer than our logs, throw away target dirs to force clippy to
// refresh the logs
if lintcheck_needs_rerun(
&config.lintcheck_results_path,
[&cargo_clippy_path, &clippy_driver_path],
) {
let shared_target_dir = "target/lintcheck/shared_target_dir";
// if we get an Err here, the shared target dir probably does simply not exist
if let Ok(metadata) = std::fs::metadata(shared_target_dir) {
if metadata.is_dir() {
println!("Clippy is newer than lint check logs, clearing lintcheck shared target dir...");
std::fs::remove_dir_all(shared_target_dir)
.expect("failed to remove target/lintcheck/shared_target_dir");
}
}
}
// assert that clippy is found
assert!(
cargo_clippy_path.is_file(),

View File

@ -1,4 +1,5 @@
#![feature(rustc_private)]
#![feature(let_chains)]
#![feature(once_cell)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
@ -71,6 +72,32 @@ fn track_clippy_args(parse_sess: &mut ParseSess, args_env_var: &Option<String>)
));
}
/// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy
/// when any of them are modified
fn track_files(parse_sess: &mut ParseSess, conf_path_string: Option<String>) {
let file_depinfo = parse_sess.file_depinfo.get_mut();
// Used by `clippy::cargo` lints and to determine the MSRV. `cargo clippy` executes `clippy-driver`
// with the current directory set to `CARGO_MANIFEST_DIR` so a relative path is fine
if Path::new("Cargo.toml").exists() {
file_depinfo.insert(Symbol::intern("Cargo.toml"));
}
// `clippy.toml`
if let Some(path) = conf_path_string {
file_depinfo.insert(Symbol::intern(&path));
}
// During development track the `clippy-driver` executable so that cargo will re-run clippy whenever
// it is rebuilt
if cfg!(debug_assertions)
&& let Ok(current_exe) = env::current_exe()
&& let Some(current_exe) = current_exe.to_str()
{
file_depinfo.insert(Symbol::intern(current_exe));
}
}
struct DefaultCallbacks;
impl rustc_driver::Callbacks for DefaultCallbacks {}
@ -97,10 +124,18 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
// JUSTIFICATION: necessary in clippy driver to set `mir_opt_level`
#[allow(rustc::bad_opt_access)]
fn config(&mut self, config: &mut interface::Config) {
let conf_path = clippy_lints::lookup_conf_file();
let conf_path_string = if let Ok(Some(path)) = &conf_path {
path.to_str().map(String::from)
} else {
None
};
let previous = config.register_lints.take();
let clippy_args_var = self.clippy_args_var.take();
config.parse_sess_created = Some(Box::new(move |parse_sess| {
track_clippy_args(parse_sess, &clippy_args_var);
track_files(parse_sess, conf_path_string);
}));
config.register_lints = Some(Box::new(move |sess, lint_store| {
// technically we're ~guaranteed that this is none but might as well call anything that
@ -109,7 +144,7 @@ fn config(&mut self, config: &mut interface::Config) {
(previous)(sess, lint_store);
}
let conf = clippy_lints::read_conf(sess);
let conf = clippy_lints::read_conf(sess, &conf_path);
clippy_lints::register_plugins(lint_store, sess, &conf);
clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf);
clippy_lints::register_renamed(lint_store);