about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Moelius <sam@moeli.us>2024-11-13 18:34:08 -0500
committerSamuel Moelius <sam@moeli.us>2024-11-15 17:37:45 -0500
commitb97ad4eccdfa8b360df243ecf21eec1fd05cb92a (patch)
tree82a9f93c731ac667503003f5a198e0f3e9c38487
parentd0f35777205090e24d5822e668cc280cab78e4ec (diff)
downloadrust-b97ad4eccdfa8b360df243ecf21eec1fd05cb92a.tar.gz
rust-b97ad4eccdfa8b360df243ecf21eec1fd05cb92a.zip
Add const parameter `REPLACEMENT_ALLOWED` to `DisallowedPath`
-rw-r--r--clippy_config/src/conf.rs2
-rw-r--r--clippy_config/src/types.rs59
-rw-r--r--clippy_lints/src/await_holding_invalid.rs9
-rw-r--r--tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs1
-rw-r--r--tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr11
-rw-r--r--tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml3
6 files changed, 67 insertions, 18 deletions
diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs
index c3b1fc83af0..82ab08530e1 100644
--- a/clippy_config/src/conf.rs
+++ b/clippy_config/src/conf.rs
@@ -445,7 +445,7 @@ define_Conf! {
     avoid_breaking_exported_api: bool = true,
     /// The list of types which may not be held across an await point.
     #[lints(await_holding_invalid_type)]
-    await_holding_invalid_types: Vec<DisallowedPath> = Vec::new(),
+    await_holding_invalid_types: Vec<DisallowedPath<false>> = Vec::new(),
     /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
     /// Use the Disallowed Names lint instead
diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs
index 122fdca726d..6a0f7aa75f2 100644
--- a/clippy_config/src/types.rs
+++ b/clippy_config/src/types.rs
@@ -14,9 +14,33 @@ pub struct Rename {
     pub rename: String,
 }
 
-#[derive(Debug, Deserialize)]
+#[derive(Debug, Serialize)]
+pub struct DisallowedPath<const REPLACEMENT_ALLOWED: bool = true> {
+    path: String,
+    reason: Option<String>,
+    replacement: Option<String>,
+}
+
+impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath<REPLACEMENT_ALLOWED> {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let enum_ = DisallowedPathEnum::deserialize(deserializer)?;
+        if !REPLACEMENT_ALLOWED && enum_.replacement().is_some() {
+            return Err(de::Error::custom("replacement not allowed for this configuration"));
+        }
+        Ok(Self {
+            path: enum_.path().to_owned(),
+            reason: enum_.reason().map(ToOwned::to_owned),
+            replacement: enum_.replacement().map(ToOwned::to_owned),
+        })
+    }
+}
+
+#[derive(Debug, Deserialize, Serialize)]
 #[serde(untagged)]
-pub enum DisallowedPath {
+pub enum DisallowedPathEnum {
     Simple(String),
     WithReason {
         path: String,
@@ -25,27 +49,33 @@ pub enum DisallowedPath {
     },
 }
 
-impl DisallowedPath {
+impl<const REPLACEMENT_ALLOWED: bool> DisallowedPath<REPLACEMENT_ALLOWED> {
     pub fn path(&self) -> &str {
-        let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
-
-        path
+        &self.path
     }
 
-    pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use<'_> {
+    pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use<'_, REPLACEMENT_ALLOWED> {
         move |diag| {
-            if let Some(replacement) = self.replacement() {
+            if let Some(replacement) = &self.replacement {
                 diag.span_suggestion(
                     span,
-                    self.reason().map_or_else(|| String::from("use"), ToOwned::to_owned),
+                    self.reason.as_ref().map_or_else(|| String::from("use"), Clone::clone),
                     replacement,
                     Applicability::MachineApplicable,
                 );
-            } else if let Some(reason) = self.reason() {
-                diag.note(reason.to_owned());
+            } else if let Some(reason) = &self.reason {
+                diag.note(reason.clone());
             }
         }
     }
+}
+
+impl DisallowedPathEnum {
+    pub fn path(&self) -> &str {
+        let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
+
+        path
+    }
 
     fn reason(&self) -> Option<&str> {
         match &self {
@@ -63,10 +93,10 @@ impl DisallowedPath {
 }
 
 /// Creates a map of disallowed items to the reason they were disallowed.
-pub fn create_disallowed_map(
+pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
     tcx: TyCtxt<'_>,
-    disallowed: &'static [DisallowedPath],
-) -> DefIdMap<(&'static str, &'static DisallowedPath)> {
+    disallowed: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
+) -> DefIdMap<(&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)> {
     disallowed
         .iter()
         .map(|x| (x.path(), x.path().split("::").collect::<Vec<_>>(), x))
@@ -466,7 +496,6 @@ macro_rules! unimplemented_serialize {
 }
 
 unimplemented_serialize! {
-    DisallowedPath,
     Rename,
     MacroMatcher,
 }
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index 3ae7ab96915..bf7f81f2f3e 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -174,7 +174,7 @@ declare_clippy_lint! {
 impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]);
 
 pub struct AwaitHolding {
-    def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>,
+    def_ids: DefIdMap<(&'static str, &'static DisallowedPath<false>)>,
 }
 
 impl AwaitHolding {
@@ -255,7 +255,12 @@ impl AwaitHolding {
     }
 }
 
-fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, disallowed_path: &'static DisallowedPath) {
+fn emit_invalid_type(
+    cx: &LateContext<'_>,
+    span: Span,
+    path: &'static str,
+    disallowed_path: &'static DisallowedPath<false>,
+) {
     span_lint_and_then(
         cx,
         AWAIT_HOLDING_INVALID_TYPE,
diff --git a/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr
new file mode 100644
index 00000000000..86e30409af0
--- /dev/null
+++ b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr
@@ -0,0 +1,11 @@
+error: error reading Clippy's configuration file: replacement not allowed for this configuration
+  --> $DIR/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml:1:31
+   |
+LL |   await-holding-invalid-types = [
+   |  _______________________________^
+LL | |     { path = "std::string::String", replacement = "std::net::Ipv4Addr" },
+LL | | ]
+   | |_^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml b/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml
new file mode 100644
index 00000000000..f6bc59672ed
--- /dev/null
+++ b/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml
@@ -0,0 +1,3 @@
+await-holding-invalid-types = [
+    { path = "std::string::String", replacement = "std::net::Ipv4Addr" },
+]