feat({unnecessary,panicking}_unwrap): lint field accesses (#15949)

Resolves https://github.com/rust-lang/rust-clippy/issues/15321

Unresolved questions:
- [ ] I did implement support for nested field accesses, but I'm not
sure if that's desired
    - It brings some additional complexity, though not too much
- It might be surprising for the user to get a lint on a direct field
access, but not a nested one
    - It's unclear how often such nested case comes up

changelog: [`unnecessary_unwrap`]: lint field accesses
changelog: [`panicking_unwrap`]: lint field accesses
This commit is contained in:
llogiq 2025-11-15 11:38:45 +00:00 committed by GitHub
commit c8e5fff413
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 670 additions and 297 deletions

View file

@ -1,15 +1,21 @@
use std::borrow::Cow;
use std::iter;
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::msrvs::Msrv;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::source::snippet;
use clippy_utils::usage::is_potentially_local_place;
use clippy_utils::{can_use_if_let_chains, higher, sym};
use rustc_abi::FieldIdx;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, UnOp};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, Place, PlaceWithHirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter;
use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::impl_lint_pass;
@ -114,11 +120,91 @@ impl UnwrappableKind {
}
}
#[derive(Clone, Debug, Eq)]
enum Local {
/// `x.field1.field2.field3`
WithFieldAccess {
local_id: HirId,
/// The indices of the field accessed.
///
/// Stored last-to-first, e.g. for the example above: `[field3, field2, field1]`
field_indices: Vec<FieldIdx>,
/// The span of the whole expression
span: Span,
},
/// `x`
Pure { local_id: HirId },
}
/// Identical to derived impl, but ignores `span` on [`Local::WithFieldAccess`]
impl PartialEq for Local {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(
Self::WithFieldAccess {
local_id: self_local_id,
field_indices: self_field_indices,
..
},
Self::WithFieldAccess {
local_id: other_local_id,
field_indices: other_field_indices,
..
},
) => self_local_id == other_local_id && self_field_indices == other_field_indices,
(
Self::Pure {
local_id: self_local_id,
},
Self::Pure {
local_id: other_local_id,
},
) => self_local_id == other_local_id,
_ => false,
}
}
}
impl Local {
fn snippet(&self, cx: &LateContext<'_>) -> Cow<'static, str> {
match *self {
Self::WithFieldAccess { span, .. } => snippet(cx.sess(), span, "_"),
Self::Pure { local_id } => cx.tcx.hir_name(local_id).to_string().into(),
}
}
fn is_potentially_local_place(&self, place: &Place<'_>) -> bool {
match self {
Self::WithFieldAccess {
local_id,
field_indices,
..
} => {
is_potentially_local_place(*local_id, place)
// If there were projections other than field projections, err on the side of caution and say that they
// _might_ be mutating something.
//
// The reason we use `<=` and not `==` is that a mutation of `struct` or `struct.field1` should count as
// mutation of the child fields such as `struct.field1.field2`
&& place.projections.len() <= field_indices.len()
&& iter::zip(&place.projections, field_indices.iter().copied().rev()).all(|(proj, field_idx)| {
match proj.kind {
ProjectionKind::Field(f_idx, _) => f_idx == field_idx,
// If this is a projection we don't expect, it _might_ be mutating something
_ => false,
}
})
},
Self::Pure { local_id } => is_potentially_local_place(*local_id, place),
}
}
}
/// Contains information about whether a variable can be unwrapped.
#[derive(Copy, Clone, Debug)]
#[derive(Clone, Debug)]
struct UnwrapInfo<'tcx> {
/// The variable that is checked
local_id: HirId,
local: Local,
/// The if itself
if_expr: &'tcx Expr<'tcx>,
/// The check, like `x.is_ok()`
@ -156,38 +242,77 @@ fn collect_unwrap_info<'tcx>(
}
}
match expr.kind {
ExprKind::Binary(op, left, right)
if matches!(
(invert, op.node),
(false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr)
) =>
{
let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false);
unwrap_info.extend(collect_unwrap_info(cx, if_expr, right, branch, invert, false));
unwrap_info
},
ExprKind::Unary(UnOp::Not, expr) => collect_unwrap_info(cx, if_expr, expr, branch, !invert, false),
ExprKind::MethodCall(method_name, receiver, [], _)
if let Some(local_id) = receiver.res_local_id()
&& let ty = cx.typeck_results().expr_ty(receiver)
&& let name = method_name.ident.name
&& let Some((kind, unwrappable)) = option_or_result_call(cx, ty, name) =>
{
let safe_to_unwrap = unwrappable != invert;
fn inner<'tcx>(
cx: &LateContext<'tcx>,
if_expr: &'tcx Expr<'_>,
expr: &'tcx Expr<'_>,
branch: &'tcx Expr<'_>,
invert: bool,
is_entire_condition: bool,
out: &mut Vec<UnwrapInfo<'tcx>>,
) {
match expr.kind {
ExprKind::Binary(op, left, right)
if matches!(
(invert, op.node),
(false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr)
) =>
{
inner(cx, if_expr, left, branch, invert, false, out);
inner(cx, if_expr, right, branch, invert, false, out);
},
ExprKind::Unary(UnOp::Not, expr) => inner(cx, if_expr, expr, branch, !invert, false, out),
ExprKind::MethodCall(method_name, receiver, [], _)
if let Some(local) = extract_local(cx, receiver)
&& let ty = cx.typeck_results().expr_ty(receiver)
&& let name = method_name.ident.name
&& let Some((kind, unwrappable)) = option_or_result_call(cx, ty, name) =>
{
let safe_to_unwrap = unwrappable != invert;
vec![UnwrapInfo {
out.push(UnwrapInfo {
local,
if_expr,
check: expr,
check_name: name,
branch,
safe_to_unwrap,
kind,
is_entire_condition,
});
},
_ => {},
}
}
let mut out = vec![];
inner(cx, if_expr, expr, branch, invert, is_entire_condition, &mut out);
out
}
/// Extracts either a local used by itself ([`Local::Pure`]), or (one or more levels of) field
/// access to a local ([`Local::WithFieldAccess`])
fn extract_local(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> Option<Local> {
let span = expr.span;
let mut field_indices = vec![];
while let ExprKind::Field(recv, _) = expr.kind
&& let Some(field_idx) = cx.typeck_results().opt_field_index(expr.hir_id)
{
field_indices.push(field_idx);
expr = recv;
}
if let Some(local_id) = expr.res_local_id() {
if field_indices.is_empty() {
Some(Local::Pure { local_id })
} else {
Some(Local::WithFieldAccess {
local_id,
if_expr,
check: expr,
check_name: name,
branch,
safe_to_unwrap,
kind,
is_entire_condition,
}]
},
_ => vec![],
field_indices,
span,
})
}
} else {
None
}
}
@ -198,9 +323,9 @@ fn collect_unwrap_info<'tcx>(
/// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if
/// the option is changed to None between `is_some` and `unwrap`, ditto for `Result`.
/// (And also `.as_mut()` is a somewhat common method that is still worth linting on.)
struct MutationVisitor<'tcx> {
struct MutationVisitor<'tcx, 'lcl> {
is_mutated: bool,
local_id: HirId,
local: &'lcl Local,
tcx: TyCtxt<'tcx>,
}
@ -221,10 +346,10 @@ fn is_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
}
}
impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx, '_> {
fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
if let ty::BorrowKind::Mutable = bk
&& is_potentially_local_place(self.local_id, &cat.place)
&& self.local.is_potentially_local_place(&cat.place)
&& !is_as_mut_use(self.tcx, diag_expr_id)
{
self.is_mutated = true;
@ -232,7 +357,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
}
fn mutate(&mut self, cat: &PlaceWithHirId<'tcx>, _: HirId) {
if is_potentially_local_place(self.local_id, &cat.place) {
if self.local.is_potentially_local_place(&cat.place) {
self.is_mutated = true;
}
}
@ -256,7 +381,7 @@ impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> {
for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) {
let mut delegate = MutationVisitor {
is_mutated: false,
local_id: unwrap_info.local_id,
local: &unwrap_info.local,
tcx: self.cx.tcx,
};
@ -318,24 +443,17 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
// find `unwrap[_err]()` or `expect("...")` calls:
if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind
&& let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg)
&& let Some(id) = self_arg.res_local_id()
&& let Some(local) = extract_local(self.cx, self_arg)
&& matches!(method_name.ident.name, sym::unwrap | sym::expect | sym::unwrap_err)
&& let call_to_unwrap = matches!(method_name.ident.name, sym::unwrap | sym::expect)
&& let Some(unwrappable) = self.unwrappables.iter()
.find(|u| u.local_id == id)
&& let Some(unwrappable) = self.unwrappables.iter().find(|u| u.local == local)
// Span contexts should not differ with the conditional branch
&& let span_ctxt = expr.span.ctxt()
&& unwrappable.branch.span.ctxt() == span_ctxt
&& unwrappable.check.span.ctxt() == span_ctxt
{
if call_to_unwrap == unwrappable.safe_to_unwrap {
let is_entire_condition = unwrappable.is_entire_condition;
let unwrappable_variable_name = self.cx.tcx.hir_name(unwrappable.local_id);
let suggested_pattern = if call_to_unwrap {
unwrappable.kind.success_variant_pattern()
} else {
unwrappable.kind.error_variant_pattern()
};
let unwrappable_variable_str = unwrappable.local.snippet(self.cx);
span_lint_hir_and_then(
self.cx,
@ -343,16 +461,21 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
expr.hir_id,
expr.span,
format!(
"called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`",
"called `{}` on `{unwrappable_variable_str}` after checking its variant with `{}`",
method_name.ident.name, unwrappable.check_name,
),
|diag| {
if is_entire_condition {
if unwrappable.is_entire_condition {
diag.span_suggestion(
unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()),
"try",
format!(
"if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}",
"if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_str}",
suggested_pattern = if call_to_unwrap {
unwrappable.kind.success_variant_pattern()
} else {
unwrappable.kind.error_variant_pattern()
},
borrow_prefix = match as_ref_kind {
Some(AsRefKind::AsRef) => "&",
Some(AsRefKind::AsMut) => "&mut ",

View file

@ -1,27 +1,19 @@
#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
#![allow(
clippy::if_same_then_else,
clippy::branches_sharing_code,
clippy::unnecessary_literal_unwrap
)]
#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
#![expect(clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap)]
fn test_complex_conditions() {
let x: Result<(), ()> = Ok(());
let y: Result<(), ()> = Ok(());
if x.is_ok() && y.is_err() {
// unnecessary
x.unwrap();
//~^ unnecessary_unwrap
// will panic
x.unwrap_err();
//~^ panicking_unwrap
// will panic
y.unwrap();
//~^ panicking_unwrap
// unnecessary
y.unwrap_err();
//~^ unnecessary_unwrap
} else {
@ -37,45 +29,35 @@ fn test_complex_conditions() {
x.unwrap();
y.unwrap();
} else {
// will panic
x.unwrap();
//~^ panicking_unwrap
// unnecessary
x.unwrap_err();
//~^ unnecessary_unwrap
// will panic
y.unwrap();
//~^ panicking_unwrap
// unnecessary
y.unwrap_err();
//~^ unnecessary_unwrap
}
let z: Result<(), ()> = Ok(());
if x.is_ok() && !(y.is_ok() || z.is_err()) {
// unnecessary
x.unwrap();
//~^ unnecessary_unwrap
// will panic
x.unwrap_err();
//~^ panicking_unwrap
// will panic
y.unwrap();
//~^ panicking_unwrap
// unnecessary
y.unwrap_err();
//~^ unnecessary_unwrap
// unnecessary
z.unwrap();
//~^ unnecessary_unwrap
// will panic
z.unwrap_err();
//~^ panicking_unwrap
}
@ -85,27 +67,21 @@ fn test_complex_conditions() {
y.unwrap();
z.unwrap();
} else {
// will panic
x.unwrap();
//~^ panicking_unwrap
// unnecessary
x.unwrap_err();
//~^ unnecessary_unwrap
// unnecessary
y.unwrap();
//~^ unnecessary_unwrap
// will panic
y.unwrap_err();
//~^ panicking_unwrap
// will panic
z.unwrap();
//~^ panicking_unwrap
// unnecessary
z.unwrap_err();
//~^ unnecessary_unwrap
}

View file

@ -1,21 +1,17 @@
error: called `unwrap` on `x` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/complex_conditionals.rs:13:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:8:9
|
LL | if x.is_ok() && y.is_err() {
| --------- the check is happening here
LL | // unnecessary
LL | x.unwrap();
| ^^^^^^^^^^
|
= help: try using `if let` or `match`
note: the lint level is defined here
--> tests/ui/checked_unwrap/complex_conditionals.rs:1:35
|
LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::unnecessary-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]`
error: this call to `unwrap_err()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:17:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:11:9
|
LL | if x.is_ok() && y.is_err() {
| --------- because of this check
@ -23,14 +19,11 @@ LL | if x.is_ok() && y.is_err() {
LL | x.unwrap_err();
| ^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> tests/ui/checked_unwrap/complex_conditionals.rs:1:9
|
LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::panicking-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]`
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:21:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:14:9
|
LL | if x.is_ok() && y.is_err() {
| ---------- because of this check
@ -39,7 +32,7 @@ LL | y.unwrap();
| ^^^^^^^^^^
error: called `unwrap_err` on `y` after checking its variant with `is_err`
--> tests/ui/checked_unwrap/complex_conditionals.rs:25:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:17:9
|
LL | if x.is_ok() && y.is_err() {
| ---------- the check is happening here
@ -50,7 +43,7 @@ LL | y.unwrap_err();
= help: try using `if let` or `match`
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:41:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:32:9
|
LL | if x.is_ok() || y.is_ok() {
| --------- because of this check
@ -59,7 +52,7 @@ LL | x.unwrap();
| ^^^^^^^^^^
error: called `unwrap_err` on `x` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/complex_conditionals.rs:45:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:35:9
|
LL | if x.is_ok() || y.is_ok() {
| --------- the check is happening here
@ -70,7 +63,7 @@ LL | x.unwrap_err();
= help: try using `if let` or `match`
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:49:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:38:9
|
LL | if x.is_ok() || y.is_ok() {
| --------- because of this check
@ -79,7 +72,7 @@ LL | y.unwrap();
| ^^^^^^^^^^
error: called `unwrap_err` on `y` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/complex_conditionals.rs:53:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:41:9
|
LL | if x.is_ok() || y.is_ok() {
| --------- the check is happening here
@ -90,18 +83,17 @@ LL | y.unwrap_err();
= help: try using `if let` or `match`
error: called `unwrap` on `x` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/complex_conditionals.rs:59:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:46:9
|
LL | if x.is_ok() && !(y.is_ok() || z.is_err()) {
| --------- the check is happening here
LL | // unnecessary
LL | x.unwrap();
| ^^^^^^^^^^
|
= help: try using `if let` or `match`
error: this call to `unwrap_err()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:63:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:49:9
|
LL | if x.is_ok() && !(y.is_ok() || z.is_err()) {
| --------- because of this check
@ -110,7 +102,7 @@ LL | x.unwrap_err();
| ^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:67:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:52:9
|
LL | if x.is_ok() && !(y.is_ok() || z.is_err()) {
| --------- because of this check
@ -119,7 +111,7 @@ LL | y.unwrap();
| ^^^^^^^^^^
error: called `unwrap_err` on `y` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/complex_conditionals.rs:71:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:55:9
|
LL | if x.is_ok() && !(y.is_ok() || z.is_err()) {
| --------- the check is happening here
@ -130,7 +122,7 @@ LL | y.unwrap_err();
= help: try using `if let` or `match`
error: called `unwrap` on `z` after checking its variant with `is_err`
--> tests/ui/checked_unwrap/complex_conditionals.rs:75:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:58:9
|
LL | if x.is_ok() && !(y.is_ok() || z.is_err()) {
| ---------- the check is happening here
@ -141,7 +133,7 @@ LL | z.unwrap();
= help: try using `if let` or `match`
error: this call to `unwrap_err()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:79:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:61:9
|
LL | if x.is_ok() && !(y.is_ok() || z.is_err()) {
| ---------- because of this check
@ -150,7 +142,7 @@ LL | z.unwrap_err();
| ^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:89:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:70:9
|
LL | if x.is_ok() || !(y.is_ok() && z.is_err()) {
| --------- because of this check
@ -159,7 +151,7 @@ LL | x.unwrap();
| ^^^^^^^^^^
error: called `unwrap_err` on `x` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/complex_conditionals.rs:93:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:73:9
|
LL | if x.is_ok() || !(y.is_ok() && z.is_err()) {
| --------- the check is happening here
@ -170,7 +162,7 @@ LL | x.unwrap_err();
= help: try using `if let` or `match`
error: called `unwrap` on `y` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/complex_conditionals.rs:97:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:76:9
|
LL | if x.is_ok() || !(y.is_ok() && z.is_err()) {
| --------- the check is happening here
@ -181,7 +173,7 @@ LL | y.unwrap();
= help: try using `if let` or `match`
error: this call to `unwrap_err()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:101:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:79:9
|
LL | if x.is_ok() || !(y.is_ok() && z.is_err()) {
| --------- because of this check
@ -190,7 +182,7 @@ LL | y.unwrap_err();
| ^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals.rs:105:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:82:9
|
LL | if x.is_ok() || !(y.is_ok() && z.is_err()) {
| ---------- because of this check
@ -199,7 +191,7 @@ LL | z.unwrap();
| ^^^^^^^^^^
error: called `unwrap_err` on `z` after checking its variant with `is_err`
--> tests/ui/checked_unwrap/complex_conditionals.rs:109:9
--> tests/ui/checked_unwrap/complex_conditionals.rs:85:9
|
LL | if x.is_ok() || !(y.is_ok() && z.is_err()) {
| ---------- the check is happening here

View file

@ -1,19 +1,14 @@
#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
#![allow(
clippy::if_same_then_else,
clippy::branches_sharing_code,
clippy::unnecessary_literal_unwrap
)]
//@no-rustfix: has placeholders
#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
#![expect(clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap)]
fn test_nested() {
fn nested() {
let x = Some(());
if x.is_some() {
// unnecessary
x.unwrap();
//~^ unnecessary_unwrap
} else {
// will panic
x.unwrap();
//~^ panicking_unwrap
}

View file

@ -1,20 +1,16 @@
error: called `unwrap` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/complex_conditionals_nested.rs:13:13
--> tests/ui/checked_unwrap/complex_conditionals_nested.rs:9:13
|
LL | if x.is_some() {
| -------------- help: try: `if let Some(<item>) = x`
LL | // unnecessary
LL | x.unwrap();
| ^^^^^^^^^^
|
note: the lint level is defined here
--> tests/ui/checked_unwrap/complex_conditionals_nested.rs:1:35
|
LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::unnecessary-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]`
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/complex_conditionals_nested.rs:17:13
--> tests/ui/checked_unwrap/complex_conditionals_nested.rs:12:13
|
LL | if x.is_some() {
| ----------- because of this check
@ -22,11 +18,8 @@ LL | if x.is_some() {
LL | x.unwrap();
| ^^^^^^^^^^
|
note: the lint level is defined here
--> tests/ui/checked_unwrap/complex_conditionals_nested.rs:1:9
|
LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::panicking-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]`
error: aborting due to 2 previous errors

View file

@ -1,5 +1,5 @@
//@require-annotations-for-level: ERROR
#![deny(clippy::unnecessary_unwrap)]
#![warn(clippy::unnecessary_unwrap)]
#[clippy::msrv = "1.85"]
fn if_let_chains_unsupported(a: Option<u32>, b: Option<u32>) {

View file

@ -8,11 +8,8 @@ LL | println!("the value of a is {}", a.unwrap());
| ^^^^^^^^^^
|
= help: try using `match`
note: the lint level is defined here
--> tests/ui/checked_unwrap/if_let_chains.rs:2:9
|
LL | #![deny(clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::unnecessary-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]`
error: called `unwrap` on `a` after checking its variant with `is_none`
--> tests/ui/checked_unwrap/if_let_chains.rs:20:42

View file

@ -1,15 +1,15 @@
//@no-rustfix: has placeholders
#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
#![allow(
#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
#![expect(
clippy::if_same_then_else,
clippy::branches_sharing_code,
clippy::unnecessary_literal_unwrap
clippy::unnecessary_literal_unwrap,
clippy::self_assignment
)]
macro_rules! m {
($a:expr) => {
if $a.is_some() {
// unnecessary
$a.unwrap();
//~^ unnecessary_unwrap
}
@ -43,90 +43,71 @@ macro_rules! checks_some {
fn main() {
let x = Some(());
if x.is_some() {
// unnecessary
x.unwrap();
//~^ unnecessary_unwrap
// unnecessary
x.expect("an error message");
//~^ unnecessary_unwrap
} else {
// will panic
x.unwrap();
//~^ panicking_unwrap
// will panic
x.expect("an error message");
//~^ panicking_unwrap
}
if x.is_none() {
// will panic
x.unwrap();
//~^ panicking_unwrap
} else {
// unnecessary
x.unwrap();
//~^ unnecessary_unwrap
}
m!(x);
// ok
checks_in_param!(x.is_some(), x.unwrap());
// ok
checks_unwrap!(x, x.unwrap());
// ok
checks_some!(x.is_some(), x);
let mut x: Result<(), ()> = Ok(());
if x.is_ok() {
// unnecessary
x.unwrap();
//~^ unnecessary_unwrap
// unnecessary
x.expect("an error message");
//~^ unnecessary_unwrap
// will panic
x.unwrap_err();
//~^ panicking_unwrap
} else {
// will panic
x.unwrap();
//~^ panicking_unwrap
// will panic
x.expect("an error message");
//~^ panicking_unwrap
// unnecessary
x.unwrap_err();
//~^ unnecessary_unwrap
}
if x.is_err() {
// will panic
x.unwrap();
//~^ panicking_unwrap
// unnecessary
x.unwrap_err();
//~^ unnecessary_unwrap
} else {
// unnecessary
x.unwrap();
//~^ unnecessary_unwrap
// will panic
x.unwrap_err();
//~^ panicking_unwrap
}
if x.is_ok() {
x = Err(());
// not unnecessary because of mutation of x
// not unnecessary because of mutation of `x`
// it will always panic but the lint is not smart enough to see this (it only
// checks if conditions).
x.unwrap();
} else {
x = Ok(());
// not unnecessary because of mutation of x
// not unnecessary because of mutation of `x`
// it will always panic but the lint is not smart enough to see this (it
// only checks if conditions).
x.unwrap_err();
@ -175,13 +156,11 @@ fn issue11371() {
//~^ panicking_unwrap
}
// This should not lint. Statics are, at the time of writing, not linted on anyway,
// but if at some point they are supported by this lint, it should correctly see that
// `X` is being mutated and not suggest `if let Some(..) = X {}`
// This should not lint and suggest `if let Some(..) = X {}`, as `X` is being mutated
static mut X: Option<i32> = Some(123);
unsafe {
#[expect(static_mut_refs)]
if X.is_some() {
//~^ ERROR: creating a shared reference
X = None;
X.unwrap();
}
@ -299,17 +278,197 @@ fn check_expect() {
let x = Some(());
if x.is_some() {
#[expect(clippy::unnecessary_unwrap)]
// unnecessary
x.unwrap();
#[expect(clippy::unnecessary_unwrap)]
// unnecessary
x.expect("an error message");
} else {
#[expect(clippy::panicking_unwrap)]
// will panic
x.unwrap();
#[expect(clippy::panicking_unwrap)]
// will panic
x.expect("an error message");
}
}
fn partial_moves() {
fn borrow_option(_: &Option<()>) {}
let x = Some(());
// Using `if let Some(o) = x` won't work here, as `borrow_option` will try to borrow a moved value
if x.is_some() {
borrow_option(&x);
x.unwrap();
//~^ unnecessary_unwrap
}
// This is fine though, as `if let Some(o) = &x` won't move `x`
if x.is_some() {
borrow_option(&x);
x.as_ref().unwrap();
//~^ unnecessary_unwrap
}
}
fn issue15321() {
struct Soption {
option: Option<bool>,
other: bool,
}
let mut sopt = Soption {
option: Some(true),
other: true,
};
// Lint: nothing was mutated
let _res = if sopt.option.is_some() {
sopt.option.unwrap()
//~^ unnecessary_unwrap
} else {
sopt.option.unwrap()
//~^ panicking_unwrap
};
// Lint: an unrelated field was mutated
let _res = if sopt.option.is_some() {
sopt.other = false;
sopt.option.unwrap()
//~^ unnecessary_unwrap
} else {
sopt.other = false;
sopt.option.unwrap()
//~^ panicking_unwrap
};
// No lint: the whole local was mutated
let _res = if sopt.option.is_some() {
sopt = sopt;
sopt.option.unwrap()
} else {
sopt.option = None;
sopt.option.unwrap()
};
// No lint: the field we're looking at was mutated
let _res = if sopt.option.is_some() {
sopt = sopt;
sopt.option.unwrap()
} else {
sopt.option = None;
sopt.option.unwrap()
};
struct Toption(Option<bool>, bool);
let mut topt = Toption(Some(true), true);
// Lint: nothing was mutated
let _res = if topt.0.is_some() {
topt.0.unwrap()
//~^ unnecessary_unwrap
} else {
topt.0.unwrap()
//~^ panicking_unwrap
};
// Lint: an unrelated field was mutated
let _res = if topt.0.is_some() {
topt.1 = false;
topt.0.unwrap()
//~^ unnecessary_unwrap
} else {
topt.1 = false;
topt.0.unwrap()
//~^ panicking_unwrap
};
// No lint: the whole local was mutated
let _res = if topt.0.is_some() {
topt = topt;
topt.0.unwrap()
} else {
topt = topt;
topt.0.unwrap()
};
// No lint: the field we're looking at was mutated
let _res = if topt.0.is_some() {
topt.0 = None;
topt.0.unwrap()
} else {
topt.0 = None;
topt.0.unwrap()
};
// Nested field accesses get linted as well
struct Soption2 {
other: bool,
option: Soption,
}
let mut sopt2 = Soption2 {
other: true,
option: Soption {
option: Some(true),
other: true,
},
};
// Lint: no fields were mutated
let _res = if sopt2.option.option.is_some() {
sopt2.option.option.unwrap()
//~^ unnecessary_unwrap
} else {
sopt2.option.option.unwrap()
//~^ panicking_unwrap
};
// Lint: an unrelated outer field was mutated -- don't get confused by `Soption2.other` having the
// same `FieldIdx` of 1 as `Soption.option`
let _res = if sopt2.option.option.is_some() {
sopt2.other = false;
sopt2.option.option.unwrap()
//~^ unnecessary_unwrap
} else {
sopt2.other = false;
sopt2.option.option.unwrap()
//~^ panicking_unwrap
};
// Lint: an unrelated inner field was mutated
let _res = if sopt2.option.option.is_some() {
sopt2.option.other = false;
sopt2.option.option.unwrap()
//~^ unnecessary_unwrap
} else {
sopt2.option.other = false;
sopt2.option.option.unwrap()
//~^ panicking_unwrap
};
// Don't lint: the whole local was mutated
let _res = if sopt2.option.option.is_some() {
sopt2 = sopt2;
sopt2.option.option.unwrap()
} else {
sopt2 = sopt2;
sopt2.option.option.unwrap()
};
// Don't lint: a parent field of the field we're looking at was mutated, and with that the
// field we're looking at
let _res = if sopt2.option.option.is_some() {
sopt2.option = sopt;
sopt2.option.option.unwrap()
} else {
sopt2.option = sopt;
sopt2.option.option.unwrap()
};
// Don't lint: the field we're looking at was mutated directly
let _res = if sopt2.option.option.is_some() {
sopt2.option.option = None;
sopt2.option.option.unwrap()
} else {
sopt2.option.option = None;
sopt2.option.option.unwrap()
};
// Partial moves
fn borrow_toption(_: &Toption) {}
// Using `if let Some(o) = topt.0` won't work here, as `borrow_toption` will try to borrow a
// partially moved value
if topt.0.is_some() {
borrow_toption(&topt);
topt.0.unwrap();
//~^ unnecessary_unwrap
}
// This is fine though, as `if let Some(o) = &topt.0` won't (partially) move `topt`
if topt.0.is_some() {
borrow_toption(&topt);
topt.0.as_ref().unwrap();
//~^ unnecessary_unwrap
}
}

View file

@ -1,20 +1,16 @@
error: called `unwrap` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:47:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:46:9
|
LL | if x.is_some() {
| -------------- help: try: `if let Some(<item>) = x`
LL | // unnecessary
LL | x.unwrap();
| ^^^^^^^^^^
|
note: the lint level is defined here
--> tests/ui/checked_unwrap/simple_conditionals.rs:2:35
|
LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::unnecessary-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]`
error: called `expect` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:51:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:49:9
|
LL | if x.is_some() {
| -------------- help: try: `if let Some(<item>) = x`
@ -23,40 +19,36 @@ LL | x.expect("an error message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:52:9
|
LL | if x.is_some() {
| ----------- because of this check
...
LL | x.unwrap();
| ^^^^^^^^^^
|
= note: `-D clippy::panicking-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]`
error: this call to `expect()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:55:9
|
LL | if x.is_some() {
| ----------- because of this check
...
LL | x.unwrap();
| ^^^^^^^^^^
|
note: the lint level is defined here
--> tests/ui/checked_unwrap/simple_conditionals.rs:2:9
|
LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `expect()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:59:9
|
LL | if x.is_some() {
| ----------- because of this check
...
LL | x.expect("an error message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:64:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:59:9
|
LL | if x.is_none() {
| ----------- because of this check
LL | // will panic
LL | x.unwrap();
| ^^^^^^^^^^
error: called `unwrap` on `x` after checking its variant with `is_none`
--> tests/ui/checked_unwrap/simple_conditionals.rs:68:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:62:9
|
LL | if x.is_none() {
| -------------- help: try: `if let Some(<item>) = x`
@ -69,7 +61,6 @@ error: called `unwrap` on `x` after checking its variant with `is_some`
|
LL | if $a.is_some() {
| --------------- help: try: `if let Some(<item>) = x`
LL | // unnecessary
LL | $a.unwrap();
| ^^^^^^^^^^^
...
@ -79,16 +70,15 @@ LL | m!(x);
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: called `unwrap` on `x` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:81:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:71:9
|
LL | if x.is_ok() {
| ------------ help: try: `if let Ok(<item>) = x`
LL | // unnecessary
LL | x.unwrap();
| ^^^^^^^^^^
error: called `expect` on `x` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:85:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:74:9
|
LL | if x.is_ok() {
| ------------ help: try: `if let Ok(<item>) = x`
@ -97,7 +87,7 @@ LL | x.expect("an error message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap_err()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:89:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:77:9
|
LL | if x.is_ok() {
| --------- because of this check
@ -106,7 +96,7 @@ LL | x.unwrap_err();
| ^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:93:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:80:9
|
LL | if x.is_ok() {
| --------- because of this check
@ -115,7 +105,7 @@ LL | x.unwrap();
| ^^^^^^^^^^
error: this call to `expect()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:97:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:83:9
|
LL | if x.is_ok() {
| --------- because of this check
@ -124,7 +114,7 @@ LL | x.expect("an error message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap_err` on `x` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:101:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:86:9
|
LL | if x.is_ok() {
| ------------ help: try: `if let Err(<item>) = x`
@ -133,16 +123,15 @@ LL | x.unwrap_err();
| ^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:106:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:90:9
|
LL | if x.is_err() {
| ---------- because of this check
LL | // will panic
LL | x.unwrap();
| ^^^^^^^^^^
error: called `unwrap_err` on `x` after checking its variant with `is_err`
--> tests/ui/checked_unwrap/simple_conditionals.rs:110:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:93:9
|
LL | if x.is_err() {
| ------------- help: try: `if let Err(<item>) = x`
@ -151,7 +140,7 @@ LL | x.unwrap_err();
| ^^^^^^^^^^^^^^
error: called `unwrap` on `x` after checking its variant with `is_err`
--> tests/ui/checked_unwrap/simple_conditionals.rs:114:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:96:9
|
LL | if x.is_err() {
| ------------- help: try: `if let Ok(<item>) = x`
@ -160,7 +149,7 @@ LL | x.unwrap();
| ^^^^^^^^^^
error: this call to `unwrap_err()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:118:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:99:9
|
LL | if x.is_err() {
| ---------- because of this check
@ -169,58 +158,58 @@ LL | x.unwrap_err();
| ^^^^^^^^^^^^^^
error: called `unwrap` on `option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:143:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:124:9
|
LL | if option.is_some() {
| ------------------- help: try: `if let Some(<item>) = &option`
LL | option.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:127:9
|
LL | if option.is_some() {
| ---------------- because of this check
...
LL | option.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `result` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:134:9
|
LL | if result.is_ok() {
| ----------------- help: try: `if let Ok(<item>) = &result`
LL | result.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:137:9
|
LL | if result.is_ok() {
| -------------- because of this check
...
LL | result.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:143:9
|
LL | if option.is_some() {
| ------------------- help: try: `if let Some(<item>) = &mut option`
LL | option.as_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:146:9
|
LL | if option.is_some() {
| ---------------- because of this check
...
LL | option.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `result` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:153:9
|
LL | if result.is_ok() {
| ----------------- help: try: `if let Ok(<item>) = &result`
LL | result.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:156:9
|
LL | if result.is_ok() {
| -------------- because of this check
...
LL | result.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:162:9
|
LL | if option.is_some() {
| ------------------- help: try: `if let Some(<item>) = &mut option`
LL | option.as_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:165:9
|
LL | if option.is_some() {
| ---------------- because of this check
...
LL | option.as_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `result` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:171:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:152:9
|
LL | if result.is_ok() {
| ----------------- help: try: `if let Ok(<item>) = &mut result`
@ -228,7 +217,7 @@ LL | result.as_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:174:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:155:9
|
LL | if result.is_ok() {
| -------------- because of this check
@ -237,7 +226,7 @@ LL | result.as_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:205:17
--> tests/ui/checked_unwrap/simple_conditionals.rs:184:17
|
LL | if option.is_some() {
| ------------------- help: try: `if let Some(<item>) = &option`
@ -245,7 +234,7 @@ LL | let _ = option.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:208:17
--> tests/ui/checked_unwrap/simple_conditionals.rs:187:17
|
LL | if option.is_some() {
| ---------------- because of this check
@ -254,7 +243,7 @@ LL | let _ = option.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `result` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:216:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:195:9
|
LL | if result.is_ok() {
| ----------------- help: try: `if let Ok(<item>) = &result`
@ -263,7 +252,7 @@ LL | result.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:220:9
--> tests/ui/checked_unwrap/simple_conditionals.rs:199:9
|
LL | if result.is_ok() {
| -------------- because of this check
@ -271,6 +260,40 @@ LL | if result.is_ok() {
LL | result.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:225:17
|
LL | if x.is_some() {
| -------------- help: try: `if let Some(<item>) = x`
LL | _ = x.unwrap();
| ^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:228:17
|
LL | if x.is_some() {
| ----------- because of this check
...
LL | _ = x.unwrap();
| ^^^^^^^^^^
error: called `unwrap` on `r` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:234:17
|
LL | if r.is_ok() {
| ------------ help: try: `if let Ok(<item>) = &r`
LL | _ = r.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:237:17
|
LL | if r.is_ok() {
| --------- because of this check
...
LL | _ = r.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:246:17
|
@ -288,42 +311,8 @@ LL | if x.is_some() {
LL | _ = x.unwrap();
| ^^^^^^^^^^
error: called `unwrap` on `r` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:255:17
|
LL | if r.is_ok() {
| ------------ help: try: `if let Ok(<item>) = &r`
LL | _ = r.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:258:17
|
LL | if r.is_ok() {
| --------- because of this check
...
LL | _ = r.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:267:17
|
LL | if x.is_some() {
| -------------- help: try: `if let Some(<item>) = x`
LL | _ = x.unwrap();
| ^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:270:17
|
LL | if x.is_some() {
| ----------- because of this check
...
LL | _ = x.unwrap();
| ^^^^^^^^^^
error: called `unwrap` on `option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:280:26
--> tests/ui/checked_unwrap/simple_conditionals.rs:259:26
|
LL | if option.is_some() {
| ------------------- help: try: `if let Some(<item>) = option`
@ -331,7 +320,7 @@ LL | println!("{:?}", option.unwrap());
| ^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:283:26
--> tests/ui/checked_unwrap/simple_conditionals.rs:262:26
|
LL | if option.is_some() {
| ---------------- because of this check
@ -340,7 +329,7 @@ LL | println!("{:?}", option.unwrap());
| ^^^^^^^^^^^^^^^
error: called `unwrap` on `result` after checking its variant with `is_ok`
--> tests/ui/checked_unwrap/simple_conditionals.rs:290:26
--> tests/ui/checked_unwrap/simple_conditionals.rs:269:26
|
LL | if result.is_ok() {
| ----------------- help: try: `if let Ok(<item>) = result`
@ -348,7 +337,7 @@ LL | println!("{:?}", result.unwrap());
| ^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:293:26
--> tests/ui/checked_unwrap/simple_conditionals.rs:272:26
|
LL | if result.is_ok() {
| -------------- because of this check
@ -356,15 +345,164 @@ LL | if result.is_ok() {
LL | println!("{:?}", result.unwrap());
| ^^^^^^^^^^^^^^^
error: creating a shared reference to mutable static
--> tests/ui/checked_unwrap/simple_conditionals.rs:183:12
error: called `unwrap` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:299:9
|
LL | if X.is_some() {
| ^^^^^^^^^^^ shared reference to mutable static
LL | if x.is_some() {
| -------------- help: try: `if let Some(<item>) = x`
LL | borrow_option(&x);
LL | x.unwrap();
| ^^^^^^^^^^
error: called `unwrap` on `x` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:305:9
|
= note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
= note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
LL | if x.is_some() {
| -------------- help: try: `if let Some(<item>) = &x`
LL | borrow_option(&x);
LL | x.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 40 previous errors
error: called `unwrap` on `sopt.option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:321:9
|
LL | let _res = if sopt.option.is_some() {
| ------------------------ help: try: `if let Some(<item>) = sopt.option`
LL | sopt.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:324:9
|
LL | let _res = if sopt.option.is_some() {
| --------------------- because of this check
...
LL | sopt.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `sopt.option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:330:9
|
LL | let _res = if sopt.option.is_some() {
| ------------------------ help: try: `if let Some(<item>) = sopt.option`
LL | sopt.other = false;
LL | sopt.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:334:9
|
LL | let _res = if sopt.option.is_some() {
| --------------------- because of this check
...
LL | sopt.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `topt.0` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:358:9
|
LL | let _res = if topt.0.is_some() {
| ------------------- help: try: `if let Some(<item>) = topt.0`
LL | topt.0.unwrap()
| ^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:361:9
|
LL | let _res = if topt.0.is_some() {
| ---------------- because of this check
...
LL | topt.0.unwrap()
| ^^^^^^^^^^^^^^^
error: called `unwrap` on `topt.0` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:367:9
|
LL | let _res = if topt.0.is_some() {
| ------------------- help: try: `if let Some(<item>) = topt.0`
LL | topt.1 = false;
LL | topt.0.unwrap()
| ^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:371:9
|
LL | let _res = if topt.0.is_some() {
| ---------------- because of this check
...
LL | topt.0.unwrap()
| ^^^^^^^^^^^^^^^
error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:405:9
|
LL | let _res = if sopt2.option.option.is_some() {
| -------------------------------- help: try: `if let Some(<item>) = sopt2.option.option`
LL | sopt2.option.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:408:9
|
LL | let _res = if sopt2.option.option.is_some() {
| ----------------------------- because of this check
...
LL | sopt2.option.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:415:9
|
LL | let _res = if sopt2.option.option.is_some() {
| -------------------------------- help: try: `if let Some(<item>) = sopt2.option.option`
LL | sopt2.other = false;
LL | sopt2.option.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:419:9
|
LL | let _res = if sopt2.option.option.is_some() {
| ----------------------------- because of this check
...
LL | sopt2.option.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:425:9
|
LL | let _res = if sopt2.option.option.is_some() {
| -------------------------------- help: try: `if let Some(<item>) = sopt2.option.option`
LL | sopt2.option.other = false;
LL | sopt2.option.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this call to `unwrap()` will always panic
--> tests/ui/checked_unwrap/simple_conditionals.rs:429:9
|
LL | let _res = if sopt2.option.option.is_some() {
| ----------------------------- because of this check
...
LL | sopt2.option.option.unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: called `unwrap` on `topt.0` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:465:9
|
LL | if topt.0.is_some() {
| ------------------- help: try: `if let Some(<item>) = topt.0`
LL | borrow_toption(&topt);
LL | topt.0.unwrap();
| ^^^^^^^^^^^^^^^
error: called `unwrap` on `topt.0` after checking its variant with `is_some`
--> tests/ui/checked_unwrap/simple_conditionals.rs:471:9
|
LL | if topt.0.is_some() {
| ------------------- help: try: `if let Some(<item>) = &topt.0`
LL | borrow_toption(&topt);
LL | topt.0.as_ref().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 57 previous errors