11use 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;
55use if_chain:: if_chain;
66use rustc_errors:: Applicability ;
77use rustc_hir as hir;
88use rustc_lint:: { LateContext , LateLintPass } ;
99use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10- use rustc_span:: symbol:: { sym, Symbol } ;
10+ use rustc_span:: symbol:: sym;
1111
1212declare_clippy_lint ! {
1313 /// ### What it does
@@ -40,28 +40,23 @@ declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
4040
4141impl LateLintPass < ' tcx > for StrlenOnCStrings {
4242 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' _ > ) {
43- if expr. span . from_expansion ( ) {
44- return ;
45- }
46-
4743 if_chain ! {
44+ if !expr. span. from_expansion( ) ;
4845 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( ) ;
5651 if path. ident. name == sym:: as_ptr;
5752 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"
6560 } else {
6661 return ;
6762 } ;
@@ -72,7 +67,7 @@ impl LateLintPass<'tcx> for StrlenOnCStrings {
7267 expr. span,
7368 "using `libc::strlen` on a `CString` or `CStr` value" ,
7469 "try this (you might also need to get rid of `unsafe` block in some cases):" ,
75- sugg ,
70+ format! ( "{}.{}().len()" , val_name , method_name ) ,
7671 Applicability :: Unspecified // Sometimes unnecessary `unsafe` block
7772 ) ;
7873 }
0 commit comments