1+ use clippy_config:: Conf ;
12use clippy_utils:: consts:: { ConstEvalCtxt , Constant } ;
23use 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 ;
58use rustc_hir:: { Expr , ExprKind } ;
69use rustc_lint:: { LateContext , LateLintPass } ;
7- use rustc_session:: declare_lint_pass ;
10+ use rustc_session:: impl_lint_pass ;
811use rustc_span:: sym;
912
1013declare_clippy_lint ! {
@@ -28,56 +31,60 @@ declare_clippy_lint! {
2831 "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
2932}
3033
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+ }
3243
3344impl < ' tcx > LateLintPass < ' tcx > for AssertionsOnConstants {
3445 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+ } ;
4976
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) ;
5478 }
79+ }
80+ }
5581
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
8289 }
8390}
0 commit comments