about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2025-03-19 15:56:45 +0000
committerGitHub <noreply@github.com>2025-03-19 15:56:45 +0000
commit48ce25ea0e02f46d2888aed2f80cf86b2dc172d6 (patch)
treeff70807b34bb7bd3a94103e28f43479b6ac9d78b
parent31497d68fb1e71f0a5facc0defec2c55260c6ac7 (diff)
parentd793c0abfa7997d65b8b52df7c8a15532c5b49df (diff)
downloadrust-48ce25ea0e02f46d2888aed2f80cf86b2dc172d6.tar.gz
rust-48ce25ea0e02f46d2888aed2f80cf86b2dc172d6.zip
Add MSRV check for `question_mark` (#14436)
changelog: [`question_mark`]: Now respects the [`msrv`] configuration
-rw-r--r--book/src/lint_configuration.md1
-rw-r--r--clippy_config/src/conf.rs1
-rw-r--r--clippy_lints/src/question_mark.rs10
-rw-r--r--clippy_utils/src/msrvs.rs1
-rw-r--r--tests/ui/question_mark.fixed21
-rw-r--r--tests/ui/question_mark.rs28
-rw-r--r--tests/ui/question_mark.stderr22
7 files changed, 80 insertions, 4 deletions
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index 3cd70ed18b5..3726d6e8a86 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -819,6 +819,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref)
 * [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or)
 * [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr)
+* [`question_mark`](https://rust-lang.github.io/rust-clippy/master/index.html#question_mark)
 * [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names)
 * [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes)
 * [`repeat_vec_with_capacity`](https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity)
diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs
index 75f68d0dc5f..798f8b3aa5a 100644
--- a/clippy_config/src/conf.rs
+++ b/clippy_config/src/conf.rs
@@ -668,6 +668,7 @@ define_Conf! {
         option_as_ref_deref,
         option_map_unwrap_or,
         ptr_as_ptr,
+        question_mark,
         redundant_field_names,
         redundant_static_lifetimes,
         repeat_vec_with_capacity,
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index 2c9d3c1ba1f..a80e1f79bbc 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -3,7 +3,7 @@ use crate::question_mark_used::QUESTION_MARK_USED;
 use clippy_config::Conf;
 use clippy_config::types::MatchLintBehaviour;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::Msrv;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
@@ -524,7 +524,8 @@ fn is_inferred_ret_closure(expr: &Expr<'_>) -> bool {
 
 impl<'tcx> LateLintPass<'tcx> for QuestionMark {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) {
+        if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) || !self.msrv.meets(cx, msrvs::QUESTION_MARK_OPERATOR)
+        {
             return;
         }
 
@@ -540,7 +541,10 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
             return;
         }
 
-        if !self.inside_try_block() && !is_in_const_context(cx) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
+        if !self.inside_try_block()
+            && !is_in_const_context(cx)
+            && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
+            && self.msrv.meets(cx, msrvs::QUESTION_MARK_OPERATOR)
         {
             check_is_none_or_err_and_early_return(cx, expr);
             check_if_let_some_or_err_and_early_return(cx, expr);
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 523e7e5aaa6..ef0f1fd40be 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -74,6 +74,7 @@ msrv_aliases! {
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
     1,16,0 { STR_REPEAT }
     1,15,0 { MAYBE_BOUND_IN_WHERE }
+    1,13,0 { QUESTION_MARK_OPERATOR }
 }
 
 /// `#[clippy::msrv]` attributes are rarely used outside of Clippy's test suite, as a basic
diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed
index 41e3910ad48..fff41f57828 100644
--- a/tests/ui/question_mark.fixed
+++ b/tests/ui/question_mark.fixed
@@ -409,3 +409,24 @@ fn issue_13417_weirder(foo: &mut StructWithOptionString, mut bar: Option<Wrapper
     //~^^^ question_mark
     Some(())
 }
+
+#[clippy::msrv = "1.12"]
+fn msrv_1_12(arg: Option<i32>) -> Option<i32> {
+    if arg.is_none() {
+        return None;
+    }
+    let val = match arg {
+        Some(val) => val,
+        None => return None,
+    };
+    println!("{}", val);
+    Some(val)
+}
+
+#[clippy::msrv = "1.13"]
+fn msrv_1_13(arg: Option<i32>) -> Option<i32> {
+    arg?;
+    let val = arg?;
+    println!("{}", val);
+    Some(val)
+}
diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs
index e570788bfdf..c71c8ee984e 100644
--- a/tests/ui/question_mark.rs
+++ b/tests/ui/question_mark.rs
@@ -496,3 +496,31 @@ fn issue_13417_weirder(foo: &mut StructWithOptionString, mut bar: Option<Wrapper
     //~^^^ question_mark
     Some(())
 }
+
+#[clippy::msrv = "1.12"]
+fn msrv_1_12(arg: Option<i32>) -> Option<i32> {
+    if arg.is_none() {
+        return None;
+    }
+    let val = match arg {
+        Some(val) => val,
+        None => return None,
+    };
+    println!("{}", val);
+    Some(val)
+}
+
+#[clippy::msrv = "1.13"]
+fn msrv_1_13(arg: Option<i32>) -> Option<i32> {
+    if arg.is_none() {
+        //~^ question_mark
+        return None;
+    }
+    let val = match arg {
+        //~^ question_mark
+        Some(val) => val,
+        None => return None,
+    };
+    println!("{}", val);
+    Some(val)
+}
diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr
index 7c80878fe81..183b8866a74 100644
--- a/tests/ui/question_mark.stderr
+++ b/tests/ui/question_mark.stderr
@@ -255,5 +255,25 @@ LL | |         return None;
 LL | |     };
    | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
 
-error: aborting due to 27 previous errors
+error: this block may be rewritten with the `?` operator
+  --> tests/ui/question_mark.rs:515:5
+   |
+LL | /     if arg.is_none() {
+LL | |
+LL | |         return None;
+LL | |     }
+   | |_____^ help: replace it with: `arg?;`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:519:15
+   |
+LL |       let val = match arg {
+   |  _______________^
+LL | |
+LL | |         Some(val) => val,
+LL | |         None => return None,
+LL | |     };
+   | |_____^ help: try instead: `arg?`
+
+error: aborting due to 29 previous errors