11use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_note} ;
2+ use clippy_utils:: get_parent_node;
23use clippy_utils:: is_must_use_func_call;
34use clippy_utils:: ty:: { is_copy, is_must_use_ty, is_type_lang_item} ;
4- use rustc_hir:: { Expr , ExprKind , LangItem } ;
5+ use rustc_hir:: { Arm , Expr , ExprKind , LangItem , Node } ;
56use rustc_lint:: { LateContext , LateLintPass } ;
67use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
78use rustc_span:: sym;
@@ -202,11 +203,13 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
202203 && let Some ( fn_name) = cx. tcx . get_diagnostic_name ( def_id)
203204 {
204205 let arg_ty = cx. typeck_results ( ) . expr_ty ( arg) ;
206+ let is_copy = is_copy ( cx, arg_ty) ;
207+ let drop_is_only_expr_in_arm = and_only_expr_in_arm ( cx, arg, expr) ;
205208 let ( lint, msg) = match fn_name {
206209 sym:: mem_drop if arg_ty. is_ref ( ) => ( DROP_REF , DROP_REF_SUMMARY ) ,
207210 sym:: mem_forget if arg_ty. is_ref ( ) => ( FORGET_REF , FORGET_REF_SUMMARY ) ,
208- sym:: mem_drop if is_copy ( cx , arg_ty ) => ( DROP_COPY , DROP_COPY_SUMMARY ) ,
209- sym:: mem_forget if is_copy ( cx , arg_ty ) => ( FORGET_COPY , FORGET_COPY_SUMMARY ) ,
211+ sym:: mem_drop if is_copy && !drop_is_only_expr_in_arm => ( DROP_COPY , DROP_COPY_SUMMARY ) ,
212+ sym:: mem_forget if is_copy => ( FORGET_COPY , FORGET_COPY_SUMMARY ) ,
210213 sym:: mem_drop if is_type_lang_item ( cx, arg_ty, LangItem :: ManuallyDrop ) => {
211214 span_lint_and_help (
212215 cx,
@@ -221,7 +224,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
221224 sym:: mem_drop
222225 if !( arg_ty. needs_drop ( cx. tcx , cx. param_env )
223226 || is_must_use_func_call ( cx, arg)
224- || is_must_use_ty ( cx, arg_ty) ) =>
227+ || is_must_use_ty ( cx, arg_ty)
228+ || drop_is_only_expr_in_arm
229+ ) =>
225230 {
226231 ( DROP_NON_DROP , DROP_NON_DROP_SUMMARY )
227232 } ,
@@ -241,3 +246,18 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
241246 }
242247 }
243248}
249+
250+ // dropping returned value of a function like in the following snippet is considered idiomatic, see
251+ // #9482 for examples match <var> {
252+ // <pat> => drop(fn_with_side_effect_and_returning_some_value()),
253+ // ..
254+ // }
255+ fn and_only_expr_in_arm < ' tcx > ( cx : & LateContext < ' tcx > , arg : & ' tcx Expr < ' _ > , drop_expr : & ' tcx Expr < ' _ > ) -> bool {
256+ if matches ! ( arg. kind, ExprKind :: Call ( ..) | ExprKind :: MethodCall ( ..) ) {
257+ let parent_node = get_parent_node ( cx. tcx , drop_expr. hir_id ) ;
258+ if let Some ( Node :: Arm ( Arm { body, .. } ) ) = & parent_node {
259+ return body. hir_id == drop_expr. hir_id ;
260+ }
261+ }
262+ false
263+ }
0 commit comments