Skip to content

Commit 72a5d7b

Browse files
committed
Add message to replace assert!(false) help
1 parent 54bf4ff commit 72a5d7b

File tree

3 files changed

+106
-9
lines changed

3 files changed

+106
-9
lines changed

clippy_lints/src/assertions_on_constants.rs

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use rustc::hir::{Expr, ExprKind};
1+
use crate::consts::{constant, Constant};
2+
use crate::utils::{is_direct_expn_of, is_expn_of, match_qpath, span_help_and_lint};
3+
use if_chain::if_chain;
4+
use rustc::hir::*;
25
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
36
use rustc::{declare_lint_pass, declare_tool_lint};
4-
5-
use crate::consts::{constant, Constant};
6-
use crate::utils::{is_direct_expn_of, is_expn_of, span_help_and_lint};
7+
use syntax::ast::LitKind;
8+
use syntax::source_map::symbol::LocalInternedString;
79

810
declare_clippy_lint! {
911
/// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls.
@@ -63,7 +65,93 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants {
6365
if assert_span.from_expansion() {
6466
return;
6567
}
66-
lint_assert_cb(false);
68+
if let Some((panic_message, is_true)) = assert_with_message(&cx, e) {
69+
if is_true {
70+
span_help_and_lint(
71+
cx,
72+
ASSERTIONS_ON_CONSTANTS,
73+
e.span,
74+
"`assert!(true)` will be optimized out by the compiler",
75+
"remove it",
76+
);
77+
} else if panic_message.starts_with("assertion failed: ") {
78+
span_help_and_lint(
79+
cx,
80+
ASSERTIONS_ON_CONSTANTS,
81+
e.span,
82+
"`assert!(false)` should probably be replaced",
83+
"use `panic!()` or `unreachable!()`",
84+
);
85+
} else {
86+
span_help_and_lint(
87+
cx,
88+
ASSERTIONS_ON_CONSTANTS,
89+
e.span,
90+
&format!("`assert!(false, \"{}\")` should probably be replaced", panic_message,),
91+
&format!(
92+
"use `panic!(\"{}\")` or `unreachable!(\"{}\")`",
93+
panic_message, panic_message,
94+
),
95+
);
96+
}
97+
}
98+
}
99+
}
100+
}
101+
102+
// fn get_assert_args(snip: String) -> Option<Vec<String>> {
103+
//
104+
// }
105+
106+
fn assert_with_message<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> Option<(LocalInternedString, bool)> {
107+
if_chain! {
108+
if let ExprKind::Match(ref expr, ref arms, MatchSource::IfDesugar { contains_else_clause: false }) = expr.kind;
109+
// match expr
110+
if let ExprKind::DropTemps(ref expr) = expr.kind;
111+
if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind;
112+
//if let ExprKind::Lit(ref lit) = expr.kind;
113+
if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables, expr);
114+
//if is_true;
115+
// match arms
116+
// arm 1 pattern
117+
if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind;
118+
if let ExprKind::Lit(ref lit) = lit_expr.kind;
119+
if let LitKind::Bool(true) = lit.node;
120+
//if let LitKind::Bool(true) = lit1.node;
121+
// arm 1 block
122+
if let ExprKind::Block(ref block1, _) = arms[0].body.kind;
123+
if let Some(trailing_expr1) = &block1.expr;
124+
if block1.stmts.len() == 0;
125+
//
126+
if let ExprKind::Block(ref actual_block1, _) = trailing_expr1.kind;
127+
if let Some(block1_expr) = &actual_block1.expr;
128+
// function call
129+
if let ExprKind::Call(ref func, ref args) = block1_expr.kind;
130+
if let ExprKind::Path(ref path) = func.kind;
131+
// ["{{root}}", "std", "rt", "begin_panic"] does not work
132+
if match_qpath(path, &["$crate", "rt", "begin_panic"]);
133+
// arguments
134+
if args.len() == 2;
135+
if let ExprKind::Lit(ref lit) = args[0].kind;
136+
if let LitKind::Str(ref s, _) = lit.node;
137+
let panic_message = s.as_str(); // bind the panic message
138+
if let ExprKind::AddrOf(MutImmutable, ref inner) = args[1].kind;
139+
if let ExprKind::Tup(ref elements) = inner.kind;
140+
if elements.len() == 3;
141+
if let ExprKind::Lit(ref lit1) = elements[0].kind;
142+
if let LitKind::Str(ref s1, _) = lit1.node;
143+
if let ExprKind::Lit(ref lit2) = elements[1].kind;
144+
if let LitKind::Int(_, _) = lit2.node;
145+
if let ExprKind::Lit(ref lit3) = elements[2].kind;
146+
if let LitKind::Int(_, _) = lit3.node;
147+
// arm 2 block
148+
if let PatKind::Wild = arms[1].pat.kind;
149+
if let ExprKind::Block(ref block2, _) = arms[1].body.kind;
150+
if let None = &block2.expr;
151+
if block2.stmts.len() == 0;
152+
then {
153+
return Some((panic_message, is_true));
67154
}
68155
}
156+
return None;
69157
}

tests/ui/assertions_on_constants.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ fn main() {
1616

1717
const C: bool = false;
1818
assert!(C);
19+
assert!(C, "C message");
1920

2021
debug_assert!(true);
2122
// Don't lint this, since there is no better way for expressing "Only panic in debug mode".

tests/ui/assertions_on_constants.stderr

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ LL | assert!(true, "true message");
2323
|
2424
= help: remove it
2525

26-
error: `assert!(false)` should probably be replaced
26+
error: `assert!(false, "false message")` should probably be replaced
2727
--> $DIR/assertions_on_constants.rs:12:5
2828
|
2929
LL | assert!(false, "false message");
3030
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3131
|
32-
= help: use `panic!()` or `unreachable!()`
32+
= help: use `panic!("false message")` or `unreachable!("false message")`
3333

3434
error: `assert!(true)` will be optimized out by the compiler
3535
--> $DIR/assertions_on_constants.rs:15:5
@@ -47,14 +47,22 @@ LL | assert!(C);
4747
|
4848
= help: use `panic!()` or `unreachable!()`
4949

50+
error: `assert!(false, "C message")` should probably be replaced
51+
--> $DIR/assertions_on_constants.rs:19:5
52+
|
53+
LL | assert!(C, "C message");
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^
55+
|
56+
= help: use `panic!("C message")` or `unreachable!("C message")`
57+
5058
error: `assert!(true)` will be optimized out by the compiler
51-
--> $DIR/assertions_on_constants.rs:20:5
59+
--> $DIR/assertions_on_constants.rs:21:5
5260
|
5361
LL | debug_assert!(true);
5462
| ^^^^^^^^^^^^^^^^^^^^
5563
|
5664
= help: remove it
5765
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
5866

59-
error: aborting due to 7 previous errors
67+
error: aborting due to 8 previous errors
6068

0 commit comments

Comments
 (0)