1
1
use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_note} ;
2
+ use clippy_utils:: get_parent_node;
2
3
use clippy_utils:: is_must_use_func_call;
3
4
use 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 } ;
5
6
use rustc_lint:: { LateContext , LateLintPass } ;
6
7
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
7
8
use rustc_span:: sym;
@@ -202,11 +203,13 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
202
203
&& let Some ( fn_name) = cx. tcx . get_diagnostic_name ( def_id)
203
204
{
204
205
let arg_ty = cx. typeck_results ( ) . expr_ty ( arg) ;
206
+ let is_copy = is_copy ( cx, arg_ty) ;
207
+ let drop_is_single_call_in_arm = is_single_call_in_arm ( cx, arg, expr) ;
205
208
let ( lint, msg) = match fn_name {
206
209
sym:: mem_drop if arg_ty. is_ref ( ) => ( DROP_REF , DROP_REF_SUMMARY ) ,
207
210
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_single_call_in_arm => ( DROP_COPY , DROP_COPY_SUMMARY ) ,
212
+ sym:: mem_forget if is_copy => ( FORGET_COPY , FORGET_COPY_SUMMARY ) ,
210
213
sym:: mem_drop if is_type_lang_item ( cx, arg_ty, LangItem :: ManuallyDrop ) => {
211
214
span_lint_and_help (
212
215
cx,
@@ -221,7 +224,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
221
224
sym:: mem_drop
222
225
if !( arg_ty. needs_drop ( cx. tcx , cx. param_env )
223
226
|| 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_single_call_in_arm
229
+ ) =>
225
230
{
226
231
( DROP_NON_DROP , DROP_NON_DROP_SUMMARY )
227
232
} ,
@@ -241,3 +246,18 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
241
246
}
242
247
}
243
248
}
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 is_single_call_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