@@ -83,3 +83,74 @@ pub(super) fn check<'tcx>(
8383 }
8484 false
8585}
86+
87+ /// lint use of `_.map_or_else(|| value, f)` for `Option`s and `Result`s that can be
88+ /// replaced with `_.map_or(value, f)`
89+ pub ( super ) fn check_map_or_else < ' tcx > (
90+ cx : & LateContext < ' tcx > ,
91+ expr : & ' tcx hir:: Expr < ' _ > ,
92+ recv : & ' tcx hir:: Expr < ' _ > ,
93+ def_arg : & ' tcx hir:: Expr < ' _ > ,
94+ map_arg : & ' tcx hir:: Expr < ' _ > ,
95+ ) {
96+ let is_option = cx. typeck_results ( ) . expr_ty ( recv) . is_diag_item ( cx, sym:: Option ) ;
97+ let is_result = cx. typeck_results ( ) . expr_ty ( recv) . is_diag_item ( cx, sym:: Result ) ;
98+
99+ if !( is_option || is_result) {
100+ return ;
101+ }
102+
103+ if let hir:: ExprKind :: Closure ( & hir:: Closure {
104+ body,
105+ fn_decl,
106+ kind : hir:: ClosureKind :: Closure ,
107+ ..
108+ } ) = def_arg. kind
109+ {
110+ let body = cx. tcx . hir_body ( body) ;
111+ let body_expr = & body. value ;
112+
113+ if usage:: BindingUsageFinder :: are_params_used ( cx, body) || is_from_proc_macro ( cx, expr) {
114+ return ;
115+ }
116+
117+ if eager_or_lazy:: switch_to_eager_eval ( cx, body_expr) {
118+ let msg = if is_option {
119+ "unnecessary closure used to substitute value for `Option::None`"
120+ } else {
121+ "unnecessary closure used to substitute value for `Result::Err`"
122+ } ;
123+ let applicability = if body
124+ . params
125+ . iter ( )
126+ . all ( |param| matches ! ( param. pat. kind, hir:: PatKind :: Binding ( ..) | hir:: PatKind :: Wild ) )
127+ && matches ! (
128+ fn_decl. output,
129+ FnRetTy :: DefaultReturn ( _)
130+ | FnRetTy :: Return ( hir:: Ty {
131+ kind: hir:: TyKind :: Infer ( ( ) ) ,
132+ ..
133+ } )
134+ ) {
135+ Applicability :: MachineApplicable
136+ } else {
137+ Applicability :: MaybeIncorrect
138+ } ;
139+
140+ if let hir:: ExprKind :: MethodCall ( .., span) = expr. kind {
141+ span_lint_and_then ( cx, UNNECESSARY_LAZY_EVALUATIONS , expr. span , msg, |diag| {
142+ diag. span_suggestion_verbose (
143+ span,
144+ "use `map_or` instead" ,
145+ format ! (
146+ "map_or({}, {})" ,
147+ snippet( cx, body_expr. span, ".." ) ,
148+ snippet( cx, map_arg. span, ".." )
149+ ) ,
150+ applicability,
151+ ) ;
152+ } ) ;
153+ }
154+ }
155+ }
156+ }
0 commit comments