From ea25ef10cf942172e09b463c305b934fabccc8e2 Mon Sep 17 00:00:00 2001
From: Andy Caldwell <andrew.caldwell@metaswitch.com>
Date: Thu, 28 Jul 2022 23:05:24 +0100
Subject: [PATCH] Harden duplicates checking and add tests

---
 clippy_lints/src/utils/conf.rs                       | 12 +++++++++---
 tests/ui-toml/conf_deprecated_key/clippy.toml        |  2 +-
 tests/ui-toml/duplicated_keys/clippy.toml            |  5 +++++
 tests/ui-toml/duplicated_keys/duplicated_keys.rs     |  1 +
 tests/ui-toml/duplicated_keys/duplicated_keys.stderr |  8 ++++++++
 5 files changed, 24 insertions(+), 4 deletions(-)
 create mode 100644 tests/ui-toml/duplicated_keys/clippy.toml
 create mode 100644 tests/ui-toml/duplicated_keys/duplicated_keys.rs
 create mode 100644 tests/ui-toml/duplicated_keys/duplicated_keys.stderr

diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 60f4b388761..1dd22cb3185 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -92,8 +92,8 @@ impl fmt::Display for ConfError {
 
 impl Error for ConfError {}
 
-fn conf_error(s: String) -> Box<dyn Error> {
-    Box::new(ConfError(s))
+fn conf_error(s: impl Into<String>) -> Box<dyn Error> {
+    Box::new(ConfError(s.into()))
 }
 
 macro_rules! define_Conf {
@@ -154,7 +154,13 @@ macro_rules! define_Conf {
                                         $name = Some(value);
                                         // $new_conf is the same as one of the defined `$name`s, so
                                         // this variable is defined in line 2 of this function.
-                                        $($new_conf = Some(value);)?
+                                        $(match $new_conf {
+                                            Some(_) => errors.push(conf_error(concat!(
+                                                "duplicate field `", stringify!($new_conf),
+                                                "` (provided as `", stringify!($name), "`)"
+                                            ))),
+                                            None => $new_conf = Some(value),
+                                        })?
                                     },
                                 }
                             }
diff --git a/tests/ui-toml/conf_deprecated_key/clippy.toml b/tests/ui-toml/conf_deprecated_key/clippy.toml
index 138160d7ac8..30cd9eecd98 100644
--- a/tests/ui-toml/conf_deprecated_key/clippy.toml
+++ b/tests/ui-toml/conf_deprecated_key/clippy.toml
@@ -1,4 +1,4 @@
-# that one is an error
+# that one is a warning
 cyclomatic-complexity-threshold = 2
 
 # that one is white-listed
diff --git a/tests/ui-toml/duplicated_keys/clippy.toml b/tests/ui-toml/duplicated_keys/clippy.toml
new file mode 100644
index 00000000000..63a893cc6c7
--- /dev/null
+++ b/tests/ui-toml/duplicated_keys/clippy.toml
@@ -0,0 +1,5 @@
+cognitive-complexity-threshold = 2
+# This is the deprecated name for the same key
+cyclomatic-complexity-threshold = 3
+# Check we get duplication warning regardless of order
+cognitive-complexity-threshold = 4
diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/tests/ui-toml/duplicated_keys/duplicated_keys.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/ui-toml/duplicated_keys/duplicated_keys.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
new file mode 100644
index 00000000000..d99490a242d
--- /dev/null
+++ b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
@@ -0,0 +1,8 @@
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`)
+
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold`
+
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+
+error: aborting due to 2 previous errors; 1 warning emitted
+