Skip to content

Commit d3a4cfd

Browse files
committed
took advice given!
1 parent 56f0182 commit d3a4cfd

File tree

6 files changed

+145
-0
lines changed

6 files changed

+145
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5515,6 +5515,7 @@ Released 2018-09-13
55155515
[`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
55165516
[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
55175517
[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
5518+
[`always_true_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#always_true_conditions
55185519
[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
55195520
[`arbitrary_source_item_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering
55205521
[`arc_with_non_send_sync`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_with_non_send_sync
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use rustc_hir::def::Res;
3+
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
4+
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_session::declare_lint_pass;
6+
7+
declare_clippy_lint! {
8+
/// ### What it does
9+
///
10+
/// ### Why is this bad?
11+
///
12+
/// ### Example
13+
/// ```no_run
14+
/// let foo = "anything";
15+
/// if foo != "thing1" || foo != "thing2" {
16+
/// println!("always executes");
17+
/// }
18+
/// ```
19+
/// Use instead:
20+
/// ```no_run
21+
/// let foo = "anything";
22+
/// if foo != "thing1" && foo != "thing2" {
23+
/// println!("sometimes executes");
24+
/// }
25+
/// ```
26+
#[clippy::version = "1.87.0"]
27+
pub ALWAYS_TRUE_CONDITIONS,
28+
nursery,
29+
"checks for if statement conditions which are always true"
30+
}
31+
32+
declare_lint_pass!(AlwaysTrueConditions => [ALWAYS_TRUE_CONDITIONS]);
33+
34+
fn context_applicable(expr: &Expr<'_>) -> Option<Res> {
35+
if let ExprKind::Binary(new_op, new_f, new_l) = expr.kind {
36+
if new_op.node == BinOpKind::Or {
37+
let f = context_applicable(new_f);
38+
let l = context_applicable(new_l);
39+
if l == f { l } else { None }
40+
} else if new_op.node == BinOpKind::Ne {
41+
find_path(new_f)
42+
} else {
43+
None
44+
}
45+
} else {
46+
None
47+
}
48+
}
49+
50+
fn find_path(expr: &Expr<'_>) -> Option<Res> {
51+
if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
52+
Some(path.res)
53+
} else {
54+
None
55+
}
56+
}
57+
58+
impl LateLintPass<'_> for AlwaysTrueConditions {
59+
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
60+
if let ExprKind::If(cond, _, _) = e.kind
61+
&& let ExprKind::DropTemps(cond) = cond.kind
62+
&& let ExprKind::Binary(f_op_kind, f_cond, l_cond) = cond.kind
63+
&& let BinOpKind::Or = f_op_kind.node
64+
{
65+
let msg = "expression will always be true, did you mean &&?";
66+
if context_applicable(f_cond) == context_applicable(l_cond) {
67+
span_lint(cx, ALWAYS_TRUE_CONDITIONS, e.span, msg);
68+
}
69+
}
70+
}
71+
}

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
pub static LINTS: &[&crate::LintInfo] = &[
66
crate::absolute_paths::ABSOLUTE_PATHS_INFO,
77
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
8+
crate::always_true_conditions::ALWAYS_TRUE_CONDITIONS_INFO,
89
crate::approx_const::APPROX_CONSTANT_INFO,
910
crate::arbitrary_source_item_ordering::ARBITRARY_SOURCE_ITEM_ORDERING_INFO,
1011
crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub mod deprecated_lints;
7474
// begin lints modules, do not remove this comment, it’s used in `update_lints`
7575
mod absolute_paths;
7676
mod almost_complete_range;
77+
mod always_true_conditions;
7778
mod approx_const;
7879
mod arbitrary_source_item_ordering;
7980
mod arc_with_non_send_sync;
@@ -944,5 +945,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
944945
store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
945946
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
946947
store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
948+
store.register_late_pass(move |_| Box::new(always_true_conditions::AlwaysTrueConditions));
947949
// add lints here, do not remove this comment, it's used in `new_lint`
948950
}

tests/ui/always_true_conditions.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#![warn(clippy::always_true_conditions)]
2+
#[allow(clippy::needless_if)]
3+
fn foo_m(name: &str) {
4+
if name != "Min" || name != "Max" || name != "Middle" {
5+
//~^ always_true_conditions
6+
println!("always prints");
7+
} else {
8+
println!("never prints");
9+
}
10+
if name != "Min" && name != "Max" {
11+
println!("condition satisfied");
12+
} else {
13+
println!("else");
14+
}
15+
}
16+
17+
fn foo_s(name: &str) {
18+
if name != "Min" || name != "Max" {
19+
//~^ always_true_conditions
20+
println!("always prints");
21+
} else {
22+
println!("never prints");
23+
}
24+
if name != "Min" && name != "Max" {
25+
println!("condition satisfied");
26+
} else {
27+
println!("else");
28+
}
29+
}
30+
31+
fn catch_or_failure(input: &str) {
32+
let b = true;
33+
if b || input != "foo" {
34+
println!("should not fire!");
35+
}
36+
}
37+
38+
fn catch_diff_var_failure(input: &str) {
39+
let b = "value";
40+
if b != "bar" || input != "foo" {
41+
println!("should not fire!");
42+
}
43+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: expression will always be true, did you mean &&?
2+
--> tests/ui/always_true_conditions.rs:4:5
3+
|
4+
LL | / if name != "Min" || name != "Max" || name != "Middle" {
5+
LL | |
6+
LL | | println!("always prints");
7+
LL | | } else {
8+
LL | | println!("never prints");
9+
LL | | }
10+
| |_____^
11+
|
12+
= note: `-D clippy::always-true-conditions` implied by `-D warnings`
13+
= help: to override `-D warnings` add `#[allow(clippy::always_true_conditions)]`
14+
15+
error: expression will always be true, did you mean &&?
16+
--> tests/ui/always_true_conditions.rs:18:5
17+
|
18+
LL | / if name != "Min" || name != "Max" {
19+
LL | |
20+
LL | | println!("always prints");
21+
LL | | } else {
22+
LL | | println!("never prints");
23+
LL | | }
24+
| |_____^
25+
26+
error: aborting due to 2 previous errors
27+

0 commit comments

Comments
 (0)