1
+ use clippy_config:: Conf ;
1
2
use clippy_utils:: consts:: { ConstEvalCtxt , Constant } ;
2
3
use clippy_utils:: diagnostics:: span_lint_and_help;
3
- use clippy_utils:: is_inside_always_const_context;
4
- use clippy_utils:: macros:: { PanicExpn , find_assert_args, root_macro_call_first_node} ;
4
+ use clippy_utils:: macros:: { find_assert_args, root_macro_call_first_node} ;
5
+ use clippy_utils:: msrvs:: Msrv ;
6
+ use clippy_utils:: { is_inside_always_const_context, msrvs} ;
7
+ use rustc_ast:: LitKind ;
5
8
use rustc_hir:: { Expr , ExprKind } ;
6
9
use rustc_lint:: { LateContext , LateLintPass } ;
7
- use rustc_session:: declare_lint_pass ;
10
+ use rustc_session:: impl_lint_pass ;
8
11
use rustc_span:: sym;
9
12
10
13
declare_clippy_lint ! {
@@ -28,56 +31,60 @@ declare_clippy_lint! {
28
31
"`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
29
32
}
30
33
31
- declare_lint_pass ! ( AssertionsOnConstants => [ ASSERTIONS_ON_CONSTANTS ] ) ;
34
+ impl_lint_pass ! ( AssertionsOnConstants => [ ASSERTIONS_ON_CONSTANTS ] ) ;
35
+ pub struct AssertionsOnConstants {
36
+ msrv : Msrv ,
37
+ }
38
+ impl AssertionsOnConstants {
39
+ pub fn new ( conf : & Conf ) -> Self {
40
+ Self { msrv : conf. msrv }
41
+ }
42
+ }
32
43
33
44
impl < ' tcx > LateLintPass < ' tcx > for AssertionsOnConstants {
34
45
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , e : & ' tcx Expr < ' _ > ) {
35
- let Some ( macro_call) = root_macro_call_first_node ( cx, e) else {
36
- return ;
37
- } ;
38
- let is_debug = match cx. tcx . get_diagnostic_name ( macro_call. def_id ) {
39
- Some ( sym:: debug_assert_macro) => true ,
40
- Some ( sym:: assert_macro) => false ,
41
- _ => return ,
42
- } ;
43
- let Some ( ( condition, panic_expn) ) = find_assert_args ( cx, e, macro_call. expn ) else {
44
- return ;
45
- } ;
46
- let Some ( Constant :: Bool ( val) ) = ConstEvalCtxt :: new ( cx) . eval ( condition) else {
47
- return ;
48
- } ;
46
+ if let Some ( macro_call) = root_macro_call_first_node ( cx, e)
47
+ && let is_debug = match cx. tcx . get_diagnostic_name ( macro_call. def_id ) {
48
+ Some ( sym:: debug_assert_macro) => true ,
49
+ Some ( sym:: assert_macro) => false ,
50
+ _ => return ,
51
+ }
52
+ && let Some ( ( condition, _) ) = find_assert_args ( cx, e, macro_call. expn )
53
+ && let Some ( ( Constant :: Bool ( assert_val) , const_src) ) =
54
+ ConstEvalCtxt :: new ( cx) . eval_with_source ( condition, macro_call. span . ctxt ( ) )
55
+ && let in_const_context = is_inside_always_const_context ( cx. tcx , e. hir_id )
56
+ && ( const_src. is_local ( ) || !in_const_context)
57
+ && !( is_debug && as_bool_lit ( condition) == Some ( false ) )
58
+ {
59
+ let ( msg, help) = if !const_src. is_local ( ) {
60
+ let help = if self . msrv . meets ( cx, msrvs:: CONST_BLOCKS ) {
61
+ "consider moving this into a const block: `const { assert!(..) }`"
62
+ } else if self . msrv . meets ( cx, msrvs:: CONST_PANIC ) {
63
+ "consider moving this to an anonymous constant: `const _: () = { assert!(..); }`"
64
+ } else {
65
+ return ;
66
+ } ;
67
+ ( "this assertion has a constant value" , help)
68
+ } else if assert_val {
69
+ ( "this assertion is always `true`" , "remove the assertion" )
70
+ } else {
71
+ (
72
+ "this assertion is always `false`" ,
73
+ "replace this with `panic!()` or `unreachable!()`" ,
74
+ )
75
+ } ;
49
76
50
- match condition. kind {
51
- ExprKind :: Path ( ..) | ExprKind :: Lit ( _) => { } ,
52
- _ if is_inside_always_const_context ( cx. tcx , e. hir_id ) => return ,
53
- _ => { } ,
77
+ span_lint_and_help ( cx, ASSERTIONS_ON_CONSTANTS , macro_call. span , msg, None , help) ;
54
78
}
79
+ }
80
+ }
55
81
56
- if val {
57
- span_lint_and_help (
58
- cx,
59
- ASSERTIONS_ON_CONSTANTS ,
60
- macro_call. span ,
61
- format ! (
62
- "`{}!(true)` will be optimized out by the compiler" ,
63
- cx. tcx. item_name( macro_call. def_id)
64
- ) ,
65
- None ,
66
- "remove it" ,
67
- ) ;
68
- } else if !is_debug {
69
- let ( assert_arg, panic_arg) = match panic_expn {
70
- PanicExpn :: Empty => ( "" , "" ) ,
71
- _ => ( ", .." , ".." ) ,
72
- } ;
73
- span_lint_and_help (
74
- cx,
75
- ASSERTIONS_ON_CONSTANTS ,
76
- macro_call. span ,
77
- format ! ( "`assert!(false{assert_arg})` should probably be replaced" ) ,
78
- None ,
79
- format ! ( "use `panic!({panic_arg})` or `unreachable!({panic_arg})`" ) ,
80
- ) ;
81
- }
82
+ fn as_bool_lit ( e : & Expr < ' _ > ) -> Option < bool > {
83
+ if let ExprKind :: Lit ( l) = e. kind
84
+ && let LitKind :: Bool ( b) = l. node
85
+ {
86
+ Some ( b)
87
+ } else {
88
+ None
82
89
}
83
90
}
0 commit comments