1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
- use clippy_utils:: paths ;
3
- use clippy_utils:: source:: snippet_with_macro_callsite ;
4
- use clippy_utils:: ty:: { is_type_diagnostic_item, is_type_ref_to_diagnostic_item } ;
2
+ use clippy_utils:: match_libc_symbol ;
3
+ use clippy_utils:: source:: snippet_with_context ;
4
+ use clippy_utils:: ty:: is_type_diagnostic_item;
5
5
use if_chain:: if_chain;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir as hir;
8
8
use rustc_lint:: { LateContext , LateLintPass } ;
9
9
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10
- use rustc_span:: symbol:: { sym, Symbol } ;
10
+ use rustc_span:: symbol:: sym;
11
11
12
12
declare_clippy_lint ! {
13
13
/// ### What it does
@@ -40,28 +40,23 @@ declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
40
40
41
41
impl LateLintPass < ' tcx > for StrlenOnCStrings {
42
42
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' _ > ) {
43
- if expr. span . from_expansion ( ) {
44
- return ;
45
- }
46
-
47
43
if_chain ! {
44
+ if !expr. span. from_expansion( ) ;
48
45
if let hir:: ExprKind :: Call ( func, [ recv] ) = expr. kind;
49
- if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = func. kind;
50
-
51
- if ( & paths:: LIBC_STRLEN ) . iter( ) . map( |x| Symbol :: intern( x) ) . eq(
52
- path. segments. iter( ) . map( |seg| seg. ident. name) ) ;
53
- if let hir:: ExprKind :: MethodCall ( path, _, args, _) = recv. kind;
54
- if args. len( ) == 1 ;
55
- if !args. iter( ) . any( |e| e. span. from_expansion( ) ) ;
46
+ if let hir:: ExprKind :: Path ( path) = & func. kind;
47
+ if let Some ( did) = cx. qpath_res( path, func. hir_id) . opt_def_id( ) ;
48
+ if match_libc_symbol( cx, did, "strlen" ) ;
49
+ if let hir:: ExprKind :: MethodCall ( path, _, [ self_arg] , _) = recv. kind;
50
+ if !recv. span. from_expansion( ) ;
56
51
if path. ident. name == sym:: as_ptr;
57
52
then {
58
- let cstring = & args [ 0 ] ;
59
- let ty = cx . typeck_results ( ) . expr_ty ( cstring ) ;
60
- let val_name = snippet_with_macro_callsite ( cx, cstring . span, ".." ) ;
61
- let sugg = if is_type_diagnostic_item( cx, ty, sym:: cstring_type) {
62
- format! ( "{}. as_bytes().len()" , val_name )
63
- } else if is_type_ref_to_diagnostic_item ( cx, ty, sym:: CStr ) {
64
- format! ( "{}. to_bytes().len()" , val_name )
53
+ let ty = cx . typeck_results ( ) . expr_ty ( self_arg ) . peel_refs ( ) ;
54
+ let mut app = Applicability :: Unspecified ;
55
+ let val_name = snippet_with_context ( cx, self_arg . span, expr . span . ctxt ( ) , ".." , & mut app ) . 0 ;
56
+ let method_name = if is_type_diagnostic_item( cx, ty, sym:: cstring_type) {
57
+ " as_bytes"
58
+ } else if is_type_diagnostic_item ( cx, ty, sym:: CStr ) {
59
+ " to_bytes"
65
60
} else {
66
61
return ;
67
62
} ;
@@ -72,7 +67,7 @@ impl LateLintPass<'tcx> for StrlenOnCStrings {
72
67
expr. span,
73
68
"using `libc::strlen` on a `CString` or `CStr` value" ,
74
69
"try this (you might also need to get rid of `unsafe` block in some cases):" ,
75
- sugg ,
70
+ format! ( "{}.{}().len()" , val_name , method_name ) ,
76
71
Applicability :: Unspecified // Sometimes unnecessary `unsafe` block
77
72
) ;
78
73
}
0 commit comments