1- use clippy_utils:: diagnostics:: span_lint_and_sugg;
2- use clippy_utils:: { ast_utils, is_direct_expn_of} ;
3- use rustc_ast:: ast:: { Expr , ExprKind , Lit , LitKind } ;
1+ use clippy_utils:: { diagnostics:: span_lint_and_sugg, higher, is_direct_expn_of, ty:: implements_trait} ;
2+ use rustc_ast:: ast:: LitKind ;
43use rustc_errors:: Applicability ;
5- use rustc_lint:: { EarlyContext , EarlyLintPass } ;
4+ use rustc_hir:: * ;
5+ use rustc_lint:: { LateContext , LateLintPass } ;
6+ use rustc_middle:: ty;
67use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
8+ use rustc_span:: symbol:: Ident ;
79
810declare_clippy_lint ! {
911 /// ### What it does
@@ -28,45 +30,77 @@ declare_clippy_lint! {
2830
2931declare_lint_pass ! ( BoolAssertComparison => [ BOOL_ASSERT_COMPARISON ] ) ;
3032
31- fn is_bool_lit ( e : & Expr ) -> bool {
33+ fn is_bool_lit ( e : & Expr < ' _ > ) -> bool {
3234 matches ! (
3335 e. kind,
3436 ExprKind :: Lit ( Lit {
35- kind : LitKind :: Bool ( _) ,
37+ node : LitKind :: Bool ( _) ,
3638 ..
3739 } )
3840 ) && !e. span . from_expansion ( )
3941}
4042
41- impl EarlyLintPass for BoolAssertComparison {
42- fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & Expr ) {
43+ fn impl_not_trait_with_bool_out ( cx : & LateContext < ' tcx > , e : & ' tcx Expr < ' _ > ) -> bool {
44+ let ty = cx. typeck_results ( ) . expr_ty ( e) ;
45+
46+ cx. tcx
47+ . lang_items ( )
48+ . not_trait ( )
49+ . filter ( |id| implements_trait ( cx, ty, * id, & [ ] ) )
50+ . and_then ( |id| {
51+ cx. tcx . associated_items ( id) . find_by_name_and_kind (
52+ cx. tcx ,
53+ Ident :: from_str ( "Output" ) ,
54+ ty:: AssocKind :: Type ,
55+ id,
56+ )
57+ } )
58+ . map_or ( false , |item| {
59+ let proj = cx. tcx . mk_projection ( item. def_id , cx. tcx . mk_substs_trait ( ty, & [ ] ) ) ;
60+ let nty = cx. tcx . normalize_erasing_regions ( cx. param_env , proj) ;
61+
62+ nty. is_bool ( )
63+ } )
64+ }
65+
66+ impl < ' tcx > LateLintPass < ' tcx > for BoolAssertComparison {
67+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
4368 let macros = [ "assert_eq" , "debug_assert_eq" ] ;
4469 let inverted_macros = [ "assert_ne" , "debug_assert_ne" ] ;
4570
4671 for mac in macros. iter ( ) . chain ( inverted_macros. iter ( ) ) {
47- if let Some ( span) = is_direct_expn_of ( e. span , mac) {
48- if let Some ( [ a, b] ) = ast_utils:: extract_assert_macro_args ( e) {
49- let nb_bool_args = is_bool_lit ( a) as usize + is_bool_lit ( b) as usize ;
72+ if let Some ( span) = is_direct_expn_of ( expr. span , mac) {
73+ if let Some ( args) = higher:: extract_assert_macro_args ( expr) {
74+ if let [ a, b, ..] = args[ ..] {
75+ let nb_bool_args = is_bool_lit ( a) as usize + is_bool_lit ( b) as usize ;
76+
77+ if nb_bool_args != 1 {
78+ // If there are two boolean arguments, we definitely don't understand
79+ // what's going on, so better leave things as is...
80+ //
81+ // Or there is simply no boolean and then we can leave things as is!
82+ return ;
83+ }
5084
51- if nb_bool_args != 1 {
52- // If there are two boolean arguments, we definitely don't understand
53- // what's going on, so better leave things as is...
54- //
55- // Or there is simply no boolean and then we can leave things as is!
85+ if !impl_not_trait_with_bool_out ( cx, a) || !impl_not_trait_with_bool_out ( cx, b) {
86+ // At this point the expression which is not a boolean
87+ // literal does not implement Not trait with a bool output,
88+ // so we cannot suggest to rewrite our code
89+ return ;
90+ }
91+
92+ let non_eq_mac = & mac[ ..mac. len ( ) - 3 ] ;
93+ span_lint_and_sugg (
94+ cx,
95+ BOOL_ASSERT_COMPARISON ,
96+ span,
97+ & format ! ( "used `{}!` with a literal bool" , mac) ,
98+ "replace it with" ,
99+ format ! ( "{}!(..)" , non_eq_mac) ,
100+ Applicability :: MaybeIncorrect ,
101+ ) ;
56102 return ;
57103 }
58-
59- let non_eq_mac = & mac[ ..mac. len ( ) - 3 ] ;
60- span_lint_and_sugg (
61- cx,
62- BOOL_ASSERT_COMPARISON ,
63- span,
64- & format ! ( "used `{}!` with a literal bool" , mac) ,
65- "replace it with" ,
66- format ! ( "{}!(..)" , non_eq_mac) ,
67- Applicability :: MaybeIncorrect ,
68- ) ;
69- return ;
70104 }
71105 }
72106 }
0 commit comments