From 605f88aab80de3e8f02d919456323702abba9f81 Mon Sep 17 00:00:00 2001
From: Alex Macleod <alex@macleod.io>
Date: Fri, 27 Sep 2024 16:56:04 +0000
Subject: [PATCH] Ignore `--print`/`-Vv` requests in `clippy-driver`

---
 src/driver.rs | 47 +++++++++++++++++++++++++++++------------------
 1 file changed, 29 insertions(+), 18 deletions(-)

diff --git a/src/driver.rs b/src/driver.rs
index 324f754e615..afd9df6c0fc 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -22,7 +22,6 @@ use rustc_span::symbol::Symbol;
 
 use std::env;
 use std::fs::read_to_string;
-use std::ops::Deref;
 use std::path::Path;
 use std::process::exit;
 
@@ -30,12 +29,8 @@ use anstream::println;
 
 /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
 /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
-fn arg_value<'a, T: Deref<Target = str>>(
-    args: &'a [T],
-    find_arg: &str,
-    pred: impl Fn(&str) -> bool,
-) -> Option<&'a str> {
-    let mut args = args.iter().map(Deref::deref);
+fn arg_value<'a>(args: &'a [String], find_arg: &str, pred: impl Fn(&str) -> bool) -> Option<&'a str> {
+    let mut args = args.iter().map(String::as_str);
     while let Some(arg) = args.next() {
         let mut arg = arg.splitn(2, '=');
         if arg.next() != Some(find_arg) {
@@ -50,11 +45,15 @@ fn arg_value<'a, T: Deref<Target = str>>(
     None
 }
 
+fn has_arg(args: &[String], find_arg: &str) -> bool {
+    args.iter().any(|arg| find_arg == arg.split('=').next().unwrap())
+}
+
 #[test]
 fn test_arg_value() {
-    let args = &["--bar=bar", "--foobar", "123", "--foo"];
+    let args = &["--bar=bar", "--foobar", "123", "--foo"].map(String::from);
 
-    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
+    assert_eq!(arg_value(&[], "--foobar", |_| true), None);
     assert_eq!(arg_value(args, "--bar", |_| false), None);
     assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
     assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
@@ -65,6 +64,16 @@ fn test_arg_value() {
     assert_eq!(arg_value(args, "--foo", |_| true), None);
 }
 
+#[test]
+fn test_has_arg() {
+    let args = &["--foo=bar", "-vV", "--baz"].map(String::from);
+    assert!(has_arg(args, "--foo"));
+    assert!(has_arg(args, "--baz"));
+    assert!(has_arg(args, "-vV"));
+
+    assert!(!has_arg(args, "--bar"));
+}
+
 fn track_clippy_args(psess: &mut ParseSess, args_env_var: &Option<String>) {
     psess.env_depinfo.get_mut().insert((
         Symbol::intern("CLIPPY_ARGS"),
@@ -189,7 +198,7 @@ pub fn main() {
         let mut orig_args = rustc_driver::args::raw_args(&early_dcx)?;
 
         let has_sysroot_arg = |args: &mut [String]| -> bool {
-            if arg_value(args, "--sysroot", |_| true).is_some() {
+            if has_arg(args, "--sysroot") {
                 return true;
             }
             // https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path
@@ -199,7 +208,7 @@ pub fn main() {
                 if let Some(arg_file_path) = arg.strip_prefix('@') {
                     if let Ok(arg_file) = read_to_string(arg_file_path) {
                         let split_arg_file: Vec<String> = arg_file.lines().map(ToString::to_string).collect();
-                        if arg_value(&split_arg_file, "--sysroot", |_| true).is_some() {
+                        if has_arg(&split_arg_file, "--sysroot") {
                             return true;
                         }
                     }
@@ -271,16 +280,18 @@ pub fn main() {
             .chain(vec!["--cfg".into(), "clippy".into()])
             .collect::<Vec<String>>();
 
-        // We enable Clippy if one of the following conditions is met
-        // - IF Clippy is run on its test suite OR
-        // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
-        //    - IF `--no-deps` is not set (`!no_deps`) OR
-        //    - IF `--no-deps` is set and Clippy is run on the specified primary package
+        // If no Clippy lints will be run we do not need to run Clippy
         let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some()
             && arg_value(&orig_args, "--force-warn", |val| val.contains("clippy::")).is_none();
-        let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
 
-        let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
+        // If `--no-deps` is enabled only lint the primary pacakge
+        let relevant_package = !no_deps || env::var("CARGO_PRIMARY_PACKAGE").is_ok();
+
+        // Do not run Clippy for Cargo's info queries so that invalid CLIPPY_ARGS are not cached
+        // https://github.com/rust-lang/cargo/issues/14385
+        let info_query = has_arg(&orig_args, "-vV") || has_arg(&orig_args, "--print");
+
+        let clippy_enabled = !cap_lints_allow && relevant_package && !info_query;
         if clippy_enabled {
             args.extend(clippy_args);
             rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })