@@ -3,10 +3,11 @@ use std::ops::ControlFlow;
33
44use clippy_utils:: comparisons:: { Rel , normalize_comparison} ;
55use clippy_utils:: diagnostics:: span_lint_and_then;
6- use clippy_utils:: macros:: { find_assert_eq_args, first_node_macro_backtrace} ;
6+ use clippy_utils:: higher:: { If , Range } ;
7+ use clippy_utils:: macros:: { find_assert_eq_args, first_node_macro_backtrace, root_macro_call} ;
78use clippy_utils:: source:: snippet;
89use clippy_utils:: visitors:: for_each_expr_without_closures;
9- use clippy_utils:: { eq_expr_value, hash_expr, higher } ;
10+ use clippy_utils:: { eq_expr_value, hash_expr} ;
1011use rustc_ast:: { BinOpKind , LitKind , RangeLimits } ;
1112use rustc_data_structures:: packed:: Pu128 ;
1213use rustc_data_structures:: unhash:: UnindexMap ;
@@ -15,7 +16,7 @@ use rustc_hir::{Block, Body, Expr, ExprKind, UnOp};
1516use rustc_lint:: { LateContext , LateLintPass } ;
1617use rustc_session:: declare_lint_pass;
1718use rustc_span:: source_map:: Spanned ;
18- use rustc_span:: { Span , sym} ;
19+ use rustc_span:: { Span , Symbol , sym} ;
1920
2021declare_clippy_lint ! {
2122 /// ### What it does
@@ -134,15 +135,15 @@ fn len_comparison<'hir>(
134135fn assert_len_expr < ' hir > (
135136 cx : & LateContext < ' _ > ,
136137 expr : & ' hir Expr < ' hir > ,
137- ) -> Option < ( LengthComparison , usize , & ' hir Expr < ' hir > ) > {
138- let ( cmp, asserted_len, slice_len) = if let Some ( higher :: If { cond, then, .. } ) = higher :: If :: hir ( expr)
138+ ) -> Option < ( LengthComparison , usize , & ' hir Expr < ' hir > , Symbol ) > {
139+ let ( ( cmp, asserted_len, slice_len) , macro_call ) = if let Some ( If { cond, then, .. } ) = If :: hir ( expr)
139140 && let ExprKind :: Unary ( UnOp :: Not , condition) = & cond. kind
140141 && let ExprKind :: Binary ( bin_op, left, right) = & condition. kind
141142 // check if `then` block has a never type expression
142143 && let ExprKind :: Block ( Block { expr : Some ( then_expr) , .. } , _) = then. kind
143144 && cx. typeck_results ( ) . expr_ty ( then_expr) . is_never ( )
144145 {
145- len_comparison ( bin_op. node , left, right) ?
146+ ( len_comparison ( bin_op. node , left, right) ?, sym :: assert_macro )
146147 } else if let Some ( ( macro_call, bin_op) ) = first_node_macro_backtrace ( cx, expr) . find_map ( |macro_call| {
147148 match cx. tcx . get_diagnostic_name ( macro_call. def_id ) {
148149 Some ( sym:: assert_eq_macro) => Some ( ( macro_call, BinOpKind :: Eq ) ) ,
@@ -151,7 +152,12 @@ fn assert_len_expr<'hir>(
151152 }
152153 } ) && let Some ( ( left, right, _) ) = find_assert_eq_args ( cx, expr, macro_call. expn )
153154 {
154- len_comparison ( bin_op, left, right) ?
155+ (
156+ len_comparison ( bin_op, left, right) ?,
157+ root_macro_call ( expr. span )
158+ . and_then ( |macro_call| cx. tcx . get_diagnostic_name ( macro_call. def_id ) )
159+ . unwrap_or ( sym:: assert_macro) ,
160+ )
155161 } else {
156162 return None ;
157163 } ;
@@ -160,7 +166,7 @@ fn assert_len_expr<'hir>(
160166 && cx. typeck_results ( ) . expr_ty_adjusted ( recv) . peel_refs ( ) . is_slice ( )
161167 && method. ident . name == sym:: len
162168 {
163- Some ( ( cmp, asserted_len, recv) )
169+ Some ( ( cmp, asserted_len, recv, macro_call ) )
164170 } else {
165171 None
166172 }
@@ -174,6 +180,7 @@ enum IndexEntry<'hir> {
174180 comparison : LengthComparison ,
175181 assert_span : Span ,
176182 slice : & ' hir Expr < ' hir > ,
183+ macro_call : Symbol ,
177184 } ,
178185 /// `assert!` with indexing
179186 ///
@@ -187,6 +194,7 @@ enum IndexEntry<'hir> {
187194 slice : & ' hir Expr < ' hir > ,
188195 indexes : Vec < Span > ,
189196 comparison : LengthComparison ,
197+ macro_call : Symbol ,
190198 } ,
191199 /// Indexing without an `assert!`
192200 IndexWithoutAssert {
@@ -225,9 +233,9 @@ fn upper_index_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<usize> {
225233 && let LitKind :: Int ( Pu128 ( index) , _) = lit. node
226234 {
227235 Some ( index as usize )
228- } else if let Some ( higher :: Range {
236+ } else if let Some ( Range {
229237 end : Some ( end) , limits, ..
230- } ) = higher :: Range :: hir ( cx, expr)
238+ } ) = Range :: hir ( cx, expr)
231239 && let ExprKind :: Lit ( lit) = & end. kind
232240 && let LitKind :: Int ( Pu128 ( index @ 1 ..) , _) = lit. node
233241 {
@@ -258,6 +266,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni
258266 comparison,
259267 assert_span,
260268 slice,
269+ macro_call,
261270 } => {
262271 if slice. span . lo ( ) > assert_span. lo ( ) {
263272 * entry = IndexEntry :: AssertWithIndex {
@@ -268,6 +277,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni
268277 slice,
269278 indexes : vec ! [ expr. span] ,
270279 comparison : * comparison,
280+ macro_call : * macro_call,
271281 } ;
272282 }
273283 } ,
@@ -303,7 +313,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni
303313
304314/// Checks if the expression is an `assert!` expression and adds it to `asserts`
305315fn check_assert < ' hir > ( cx : & LateContext < ' _ > , expr : & ' hir Expr < ' hir > , map : & mut UnindexMap < u64 , Vec < IndexEntry < ' hir > > > ) {
306- if let Some ( ( comparison, asserted_len, slice) ) = assert_len_expr ( cx, expr) {
316+ if let Some ( ( comparison, asserted_len, slice, macro_call ) ) = assert_len_expr ( cx, expr) {
307317 let hash = hash_expr ( cx, slice) ;
308318 let indexes = map. entry ( hash) . or_default ( ) ;
309319
@@ -326,6 +336,7 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un
326336 assert_span : expr. span . source_callsite ( ) ,
327337 comparison,
328338 asserted_len,
339+ macro_call,
329340 } ;
330341 }
331342 } else {
@@ -334,6 +345,7 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un
334345 comparison,
335346 assert_span : expr. span . source_callsite ( ) ,
336347 slice,
348+ macro_call,
337349 } ) ;
338350 }
339351 }
@@ -362,6 +374,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap<u64, Vec<IndexEntry<'_>
362374 comparison,
363375 assert_span,
364376 slice,
377+ macro_call,
365378 } if indexes. len ( ) > 1 && !is_first_highest => {
366379 // if we have found an `assert!`, let's also check that it's actually right
367380 // and if it covers the highest index and if not, suggest the correct length
@@ -382,11 +395,23 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap<u64, Vec<IndexEntry<'_>
382395 snippet( cx, slice. span, ".." )
383396 ) ) ,
384397 // `highest_index` here is rather a length, so we need to add 1 to it
385- LengthComparison :: LengthEqualInt if asserted_len < highest_index + 1 => Some ( format ! (
386- "assert!({}.len() == {})" ,
387- snippet( cx, slice. span, ".." ) ,
388- highest_index + 1
389- ) ) ,
398+ LengthComparison :: LengthEqualInt if asserted_len < highest_index + 1 => match macro_call {
399+ sym:: assert_eq_macro => Some ( format ! (
400+ "assert_eq!({}.len(), {})" ,
401+ snippet( cx, slice. span, ".." ) ,
402+ highest_index + 1
403+ ) ) ,
404+ sym:: debug_assert_eq_macro => Some ( format ! (
405+ "debug_assert_eq!({}.len(), {})" ,
406+ snippet( cx, slice. span, ".." ) ,
407+ highest_index + 1
408+ ) ) ,
409+ _ => Some ( format ! (
410+ "assert!({}.len() == {})" ,
411+ snippet( cx, slice. span, ".." ) ,
412+ highest_index + 1
413+ ) ) ,
414+ } ,
390415 _ => None ,
391416 } ;
392417
0 commit comments