1- use clippy_utils:: diagnostics:: span_lint_and_sugg;
2- use rustc_ast:: ast:: { BorrowKind , Expr , ExprKind , Mutability } ;
3- use rustc_ast:: token:: { Lit , LitKind } ;
1+ use std:: borrow:: Cow ;
2+
3+ use clippy_utils:: diagnostics:: span_lint_and_then;
4+ use clippy_utils:: source:: snippet_with_applicability;
5+ use clippy_utils:: sugg:: Sugg ;
6+ use clippy_utils:: { get_parent_expr, span_contains_cfg, span_contains_comment} ;
7+ use rustc_ast:: LitKind ;
48use rustc_errors:: Applicability ;
5- use rustc_lint:: { EarlyContext , EarlyLintPass } ;
9+ use rustc_hir:: { BorrowKind , Expr , ExprKind , Mutability } ;
10+ use rustc_lint:: { LateContext , LateLintPass } ;
611use rustc_session:: declare_lint_pass;
12+ use rustc_span:: Span ;
713
814declare_clippy_lint ! {
915 /// ### What it does
@@ -30,47 +36,73 @@ declare_clippy_lint! {
3036
3137declare_lint_pass ! ( ByteCharSlice => [ BYTE_CHAR_SLICES ] ) ;
3238
33- impl EarlyLintPass for ByteCharSlice {
34- fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & Expr ) {
39+ impl < ' tcx > LateLintPass < ' tcx > for ByteCharSlice {
40+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
3541 if !expr. span . from_expansion ( )
36- && let Some ( slice) = is_byte_char_slices ( expr)
42+ && let Some ( ( has_ref , slice) ) = is_byte_char_slices ( cx , expr)
3743 {
38- span_lint_and_sugg (
44+ span_lint_and_then (
3945 cx,
4046 BYTE_CHAR_SLICES ,
4147 expr. span ,
4248 "can be more succinctly written as a byte str" ,
43- "try" ,
44- format ! ( "b\" {slice}\" " ) ,
45- Applicability :: MachineApplicable ,
49+ |diag| {
50+ let mut app = Applicability :: MachineApplicable ;
51+ let mut sugg = Sugg :: hir_from_snippet ( cx, expr, |_| {
52+ let mut slice = slice. iter ( ) . fold ( "b\" " . to_owned ( ) , |mut acc, span| {
53+ let snippet = snippet_with_applicability ( cx, * span, "b'?'" , & mut app) ;
54+ acc. push_str ( match & snippet[ 2 ..snippet. len ( ) - 1 ] {
55+ "\" " => "\\ \" " ,
56+ "\\ '" => "'" ,
57+ other => other,
58+ } ) ;
59+ acc
60+ } ) ;
61+ slice. push ( '"' ) ;
62+ Cow :: Owned ( slice)
63+ } ) ;
64+ if !has_ref && !cx. typeck_results ( ) . expr_ty_adjusted ( expr) . is_array_slice ( ) {
65+ sugg = sugg. deref ( ) ;
66+ }
67+
68+ diag. span_suggestion ( expr. span , "try" , sugg, app) ;
69+ } ,
4670 ) ;
4771 }
4872 }
4973}
5074
5175/// Checks whether the slice is that of byte chars, and if so, builds a byte-string out of it
52- fn is_byte_char_slices ( expr : & Expr ) -> Option < String > {
53- if let ExprKind :: AddrOf ( BorrowKind :: Ref , Mutability :: Not , expr) = & expr. kind
54- && let ExprKind :: Array ( members) = & expr. kind
76+ fn is_byte_char_slices < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) -> Option < ( bool , Vec < Span > ) > {
77+ let ( has_ref, expr) = if let ExprKind :: AddrOf ( BorrowKind :: Ref , Mutability :: Not , inner) = expr. kind {
78+ ( true , inner)
79+ } else if let Some ( parent) = get_parent_expr ( cx, expr) // Already checked by the parent expr.
80+ && let ExprKind :: AddrOf ( BorrowKind :: Ref , Mutability :: Not , _) = parent. kind
81+ {
82+ return None ;
83+ } else {
84+ ( false , expr)
85+ } ;
86+
87+ if let ExprKind :: Array ( members) = expr. kind
5588 && !members. is_empty ( )
89+ && !span_contains_comment ( cx, expr. span )
90+ && !span_contains_cfg ( cx, expr. span )
5691 {
57- members
92+ return members
5893 . iter ( )
59- . map ( |member| match & member. kind {
60- ExprKind :: Lit ( Lit {
61- kind : LitKind :: Byte ,
62- symbol,
63- ..
64- } ) => Some ( symbol. as_str ( ) ) ,
65- _ => None ,
66- } )
67- . map ( |maybe_quote| match maybe_quote {
68- Some ( "\" " ) => Some ( "\\ \" " ) ,
69- Some ( "\\ '" ) => Some ( "'" ) ,
70- other => other,
94+ . try_fold ( Vec :: new ( ) , |mut acc, member| {
95+ if let ExprKind :: Lit ( lit) = member. kind
96+ && let LitKind :: Byte ( _) = lit. node
97+ && expr. span . eq_ctxt ( member. span )
98+ {
99+ acc. push ( lit. span ) ;
100+ return Some ( acc) ;
101+ }
102+ None
71103 } )
72- . collect :: < Option < String > > ( )
73- } else {
74- None
104+ . map ( |s| ( has_ref, s) ) ;
75105 }
106+
107+ None
76108}
0 commit comments