Skip to content

Commit fd2d8be

Browse files
committed
Auto merge of rust-lang#10293 - Alexendoo:bool-assert-comparison-negation, r=dswij
Negate suggestions when needed in `bool_assert_comparison` changelog: none assuming this gets into the same release as rust-lang#10218 Fixes rust-lang#10291 r? `@dswij` Thanks to `@black-puppydog` for spotting it early
2 parents 3bb6ee5 + 5546c82 commit fd2d8be

File tree

4 files changed

+176
-51
lines changed

4 files changed

+176
-51
lines changed

clippy_lints/src/bool_assert_comparison.rs

+31-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
3+
use clippy_utils::sugg::Sugg;
34
use clippy_utils::ty::{implements_trait, is_copy};
45
use rustc_ast::ast::LitKind;
56
use rustc_errors::Applicability;
@@ -34,14 +35,16 @@ declare_clippy_lint! {
3435

3536
declare_lint_pass!(BoolAssertComparison => [BOOL_ASSERT_COMPARISON]);
3637

37-
fn is_bool_lit(e: &Expr<'_>) -> bool {
38-
matches!(
39-
e.kind,
40-
ExprKind::Lit(Lit {
41-
node: LitKind::Bool(_),
42-
..
43-
})
44-
) && !e.span.from_expansion()
38+
fn extract_bool_lit(e: &Expr<'_>) -> Option<bool> {
39+
if let ExprKind::Lit(Lit {
40+
node: LitKind::Bool(b), ..
41+
}) = e.kind
42+
&& !e.span.from_expansion()
43+
{
44+
Some(b)
45+
} else {
46+
None
47+
}
4548
}
4649

4750
fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -69,24 +72,23 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
6972
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
7073
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
7174
let macro_name = cx.tcx.item_name(macro_call.def_id);
72-
if !matches!(
73-
macro_name.as_str(),
74-
"assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne"
75-
) {
76-
return;
77-
}
75+
let eq_macro = match macro_name.as_str() {
76+
"assert_eq" | "debug_assert_eq" => true,
77+
"assert_ne" | "debug_assert_ne" => false,
78+
_ => return,
79+
};
7880
let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
7981

8082
let a_span = a.span.source_callsite();
8183
let b_span = b.span.source_callsite();
8284

83-
let (lit_span, non_lit_expr) = match (is_bool_lit(a), is_bool_lit(b)) {
84-
// assert_eq!(true, b)
85-
// ^^^^^^
86-
(true, false) => (a_span.until(b_span), b),
87-
// assert_eq!(a, true)
88-
// ^^^^^^
89-
(false, true) => (b_span.with_lo(a_span.hi()), a),
85+
let (lit_span, bool_value, non_lit_expr) = match (extract_bool_lit(a), extract_bool_lit(b)) {
86+
// assert_eq!(true/false, b)
87+
// ^^^^^^^^^^^^
88+
(Some(bool_value), None) => (a_span.until(b_span), bool_value, b),
89+
// assert_eq!(a, true/false)
90+
// ^^^^^^^^^^^^
91+
(None, Some(bool_value)) => (b_span.with_lo(a_span.hi()), bool_value, a),
9092
// If there are two boolean arguments, we definitely don't understand
9193
// what's going on, so better leave things as is...
9294
//
@@ -121,9 +123,16 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
121123
// ^^^^^^^^^
122124
let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
123125

126+
let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
127+
128+
if bool_value ^ eq_macro {
129+
let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else { return };
130+
suggestions.push((non_lit_expr.span, (!sugg).to_string()));
131+
}
132+
124133
diag.multipart_suggestion(
125134
format!("replace it with `{non_eq_mac}!(..)`"),
126-
vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())],
135+
suggestions,
127136
Applicability::MachineApplicable,
128137
);
129138
},

tests/ui/bool_assert_comparison.fixed

+24-14
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn main() {
8686
let b = ImplNotTraitWithBool;
8787

8888
assert_eq!("a".len(), 1);
89-
assert!("a".is_empty());
89+
assert!(!"a".is_empty());
9090
assert!("".is_empty());
9191
assert!("".is_empty());
9292
assert_eq!(a!(), b!());
@@ -97,16 +97,16 @@ fn main() {
9797

9898
assert_ne!("a".len(), 1);
9999
assert!("a".is_empty());
100-
assert!("".is_empty());
101-
assert!("".is_empty());
100+
assert!(!"".is_empty());
101+
assert!(!"".is_empty());
102102
assert_ne!(a!(), b!());
103103
assert_ne!(a!(), "".is_empty());
104104
assert_ne!("".is_empty(), b!());
105105
assert_ne!(a, true);
106-
assert!(b);
106+
assert!(!b);
107107

108108
debug_assert_eq!("a".len(), 1);
109-
debug_assert!("a".is_empty());
109+
debug_assert!(!"a".is_empty());
110110
debug_assert!("".is_empty());
111111
debug_assert!("".is_empty());
112112
debug_assert_eq!(a!(), b!());
@@ -117,27 +117,27 @@ fn main() {
117117

118118
debug_assert_ne!("a".len(), 1);
119119
debug_assert!("a".is_empty());
120-
debug_assert!("".is_empty());
121-
debug_assert!("".is_empty());
120+
debug_assert!(!"".is_empty());
121+
debug_assert!(!"".is_empty());
122122
debug_assert_ne!(a!(), b!());
123123
debug_assert_ne!(a!(), "".is_empty());
124124
debug_assert_ne!("".is_empty(), b!());
125125
debug_assert_ne!(a, true);
126-
debug_assert!(b);
126+
debug_assert!(!b);
127127

128128
// assert with error messages
129129
assert_eq!("a".len(), 1, "tadam {}", 1);
130130
assert_eq!("a".len(), 1, "tadam {}", true);
131-
assert!("a".is_empty(), "tadam {}", 1);
132-
assert!("a".is_empty(), "tadam {}", true);
133-
assert!("a".is_empty(), "tadam {}", true);
131+
assert!(!"a".is_empty(), "tadam {}", 1);
132+
assert!(!"a".is_empty(), "tadam {}", true);
133+
assert!(!"a".is_empty(), "tadam {}", true);
134134
assert_eq!(a, true, "tadam {}", false);
135135

136136
debug_assert_eq!("a".len(), 1, "tadam {}", 1);
137137
debug_assert_eq!("a".len(), 1, "tadam {}", true);
138-
debug_assert!("a".is_empty(), "tadam {}", 1);
139-
debug_assert!("a".is_empty(), "tadam {}", true);
140-
debug_assert!("a".is_empty(), "tadam {}", true);
138+
debug_assert!(!"a".is_empty(), "tadam {}", 1);
139+
debug_assert!(!"a".is_empty(), "tadam {}", true);
140+
debug_assert!(!"a".is_empty(), "tadam {}", true);
141141
debug_assert_eq!(a, true, "tadam {}", false);
142142

143143
assert!(a!());
@@ -158,4 +158,14 @@ fn main() {
158158
}};
159159
}
160160
in_macro!(a);
161+
162+
assert!("".is_empty());
163+
assert!("".is_empty());
164+
assert!(!"requires negation".is_empty());
165+
assert!(!"requires negation".is_empty());
166+
167+
debug_assert!("".is_empty());
168+
debug_assert!("".is_empty());
169+
debug_assert!(!"requires negation".is_empty());
170+
debug_assert!(!"requires negation".is_empty());
161171
}

tests/ui/bool_assert_comparison.rs

+10
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,14 @@ fn main() {
158158
}};
159159
}
160160
in_macro!(a);
161+
162+
assert_eq!("".is_empty(), true);
163+
assert_ne!("".is_empty(), false);
164+
assert_ne!("requires negation".is_empty(), true);
165+
assert_eq!("requires negation".is_empty(), false);
166+
167+
debug_assert_eq!("".is_empty(), true);
168+
debug_assert_ne!("".is_empty(), false);
169+
debug_assert_ne!("requires negation".is_empty(), true);
170+
debug_assert_eq!("requires negation".is_empty(), false);
161171
}

0 commit comments

Comments
 (0)