1- use rustc_hir:: { Expr , ExprKind , HirId , Stmt , StmtKind } ;
2- use rustc_middle:: ty:: { self , Ty } ;
1+ use rustc_hir:: { Expr , ExprKind , Stmt , StmtKind } ;
2+ use rustc_middle:: ty:: { self } ;
33use rustc_session:: { declare_lint, declare_lint_pass} ;
4+ use rustc_span:: sym;
45
56use crate :: lints:: MappingToUnit ;
67use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -39,58 +40,43 @@ declare_lint_pass!(MapUnitFn => [MAP_UNIT_FN]);
3940
4041impl < ' tcx > LateLintPass < ' tcx > for MapUnitFn {
4142 fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & Stmt < ' _ > ) {
42- if stmt . span . from_expansion ( ) {
43+ let StmtKind :: Semi ( expr ) = stmt . kind else {
4344 return ;
44- }
45-
46- if let StmtKind :: Semi ( expr) = stmt. kind
47- && let ExprKind :: MethodCall ( path, receiver, args, span) = expr. kind
45+ } ;
46+ let ExprKind :: MethodCall ( path, receiver, [ arg] , span) = expr. kind else {
47+ return ;
48+ } ;
49+ if path. ident . name != sym:: map
50+ || stmt. span . from_expansion ( )
51+ || receiver. span . from_expansion ( )
52+ || arg. span . from_expansion ( )
53+ || !is_impl_slice ( cx, receiver)
54+ || !cx
55+ . typeck_results ( )
56+ . type_dependent_def_id ( expr. hir_id )
57+ . is_some_and ( |id| cx. tcx . is_diagnostic_item ( sym:: IteratorMap , id) )
4858 {
49- if path. ident . name . as_str ( ) == "map" {
50- if receiver. span . from_expansion ( )
51- || args. iter ( ) . any ( |e| e. span . from_expansion ( ) )
52- || !is_impl_slice ( cx, receiver)
53- || !is_diagnostic_name ( cx, expr. hir_id , "IteratorMap" )
54- {
55- return ;
56- }
57- let arg_ty = cx. typeck_results ( ) . expr_ty ( & args[ 0 ] ) ;
58- let default_span = args[ 0 ] . span ;
59- if let ty:: FnDef ( id, _) = arg_ty. kind ( ) {
60- let fn_ty = cx. tcx . fn_sig ( id) . skip_binder ( ) ;
61- let ret_ty = fn_ty. output ( ) . skip_binder ( ) ;
62- if is_unit_type ( ret_ty) {
63- cx. emit_span_lint (
64- MAP_UNIT_FN ,
65- span,
66- MappingToUnit {
67- function_label : cx. tcx . span_of_impl ( * id) . unwrap_or ( default_span) ,
68- argument_label : args[ 0 ] . span ,
69- map_label : span,
70- suggestion : path. ident . span ,
71- replace : "for_each" . to_string ( ) ,
72- } ,
73- )
74- }
75- } else if let ty:: Closure ( id, subs) = arg_ty. kind ( ) {
76- let cl_ty = subs. as_closure ( ) . sig ( ) ;
77- let ret_ty = cl_ty. output ( ) . skip_binder ( ) ;
78- if is_unit_type ( ret_ty) {
79- cx. emit_span_lint (
80- MAP_UNIT_FN ,
81- span,
82- MappingToUnit {
83- function_label : cx. tcx . span_of_impl ( * id) . unwrap_or ( default_span) ,
84- argument_label : args[ 0 ] . span ,
85- map_label : span,
86- suggestion : path. ident . span ,
87- replace : "for_each" . to_string ( ) ,
88- } ,
89- )
90- }
91- }
92- }
59+ return ;
9360 }
61+ let ( id, sig) = match * cx. typeck_results ( ) . expr_ty ( arg) . kind ( ) {
62+ ty:: Closure ( id, subs) => ( id, subs. as_closure ( ) . sig ( ) ) ,
63+ ty:: FnDef ( id, _) => ( id, cx. tcx . fn_sig ( id) . skip_binder ( ) ) ,
64+ _ => return ,
65+ } ;
66+ let ret_ty = sig. output ( ) . skip_binder ( ) ;
67+ if !( ret_ty. is_unit ( ) || ret_ty. is_never ( ) ) {
68+ return ;
69+ }
70+ cx. emit_span_lint (
71+ MAP_UNIT_FN ,
72+ span,
73+ MappingToUnit {
74+ function_label : cx. tcx . span_of_impl ( id) . unwrap_or ( arg. span ) ,
75+ argument_label : arg. span ,
76+ map_label : span,
77+ suggestion : path. ident . span ,
78+ } ,
79+ ) ;
9480 }
9581}
9682
@@ -102,18 +88,3 @@ fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
10288 }
10389 false
10490}
105-
106- fn is_unit_type ( ty : Ty < ' _ > ) -> bool {
107- ty. is_unit ( ) || ty. is_never ( )
108- }
109-
110- fn is_diagnostic_name ( cx : & LateContext < ' _ > , id : HirId , name : & str ) -> bool {
111- if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( id)
112- && let Some ( item) = cx. tcx . get_diagnostic_name ( def_id)
113- {
114- if item. as_str ( ) == name {
115- return true ;
116- }
117- }
118- false
119- }
0 commit comments