@@ -275,7 +275,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
275275 && !stmt. span . in_external_macro ( cx. sess ( ) . source_map ( ) )
276276 && let ctxt = stmt. span . ctxt ( )
277277 && expr. span . ctxt ( ) == ctxt
278- && let Some ( reduced) = reduce_expression ( cx, expr)
278+ && let Some ( ( reduced, applicability ) ) = reduce_expression ( cx, expr)
279279 && reduced. iter ( ) . all ( |e| e. span . ctxt ( ) == ctxt)
280280 {
281281 if let ExprKind :: Index ( ..) = & expr. kind {
@@ -318,48 +318,72 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
318318 stmt. span ,
319319 "unnecessary operation" ,
320320 |diag| {
321- diag. span_suggestion (
322- stmt. span ,
323- "statement can be reduced to" ,
324- snippet,
325- Applicability :: MachineApplicable ,
326- ) ;
321+ diag. span_suggestion ( stmt. span , "statement can be reduced to" , snippet, applicability) ;
327322 } ,
328323 ) ;
329324 }
330325 }
331326}
332327
333- fn reduce_expression < ' a > ( cx : & LateContext < ' _ > , expr : & ' a Expr < ' a > ) -> Option < Vec < & ' a Expr < ' a > > > {
328+ fn reduce_expression < ' a > ( cx : & LateContext < ' _ > , expr : & ' a Expr < ' a > ) -> Option < ( Vec < & ' a Expr < ' a > > , Applicability ) > {
334329 if expr. span . from_expansion ( ) {
335330 return None ;
336331 }
337332 match expr. kind {
338- ExprKind :: Index ( a, b, _) => Some ( vec ! [ a, b] ) ,
333+ ExprKind :: Index ( a, b, _) => Some ( ( vec ! [ a, b] , Applicability :: MachineApplicable ) ) ,
339334 ExprKind :: Binary ( ref binop, a, b) if binop. node != BinOpKind :: And && binop. node != BinOpKind :: Or => {
340- Some ( vec ! [ a, b] )
335+ Some ( ( vec ! [ a, b] , Applicability :: MachineApplicable ) )
341336 } ,
342- ExprKind :: Array ( v) | ExprKind :: Tup ( v) => Some ( v. iter ( ) . collect ( ) ) ,
337+ ExprKind :: Array ( elems) => {
338+ let applicability = if elems. iter ( ) . all ( |elem| expr_type_is_certain ( cx, elem) ) {
339+ Applicability :: MachineApplicable
340+ } else {
341+ // there's a risk that, if we take the elem exprs out of the context of the array,
342+ // their types might become ambiguous
343+ Applicability :: MaybeIncorrect
344+ } ;
345+ Some ( ( elems. iter ( ) . collect ( ) , applicability) )
346+ } ,
347+ ExprKind :: Tup ( v) => Some ( ( v. iter ( ) . collect ( ) , Applicability :: MachineApplicable ) ) ,
343348 ExprKind :: Repeat ( inner, _)
344349 | ExprKind :: Type ( inner, _)
345350 | ExprKind :: Unary ( _, inner)
346351 | ExprKind :: Field ( inner, _)
347- | ExprKind :: AddrOf ( _, _, inner) => reduce_expression ( cx, inner) . or_else ( || Some ( vec ! [ inner] ) ) ,
352+ | ExprKind :: AddrOf ( _, _, inner) => {
353+ reduce_expression ( cx, inner) . or_else ( || Some ( ( vec ! [ inner] , Applicability :: MachineApplicable ) ) )
354+ } ,
348355 ExprKind :: Cast ( inner, _) if expr_type_is_certain ( cx, inner) => {
349- reduce_expression ( cx, inner) . or_else ( || Some ( vec ! [ inner] ) )
356+ reduce_expression ( cx, inner) . or_else ( || Some ( ( vec ! [ inner] , Applicability :: MachineApplicable ) ) )
350357 } ,
351358 ExprKind :: Struct ( _, fields, ref base) => {
359+ let applicability = if fields. iter ( ) . all ( |f| expr_type_is_certain ( cx, f. expr ) ) {
360+ Applicability :: MachineApplicable
361+ } else {
362+ // there's a risk that, if we take the field exprs out of the context of the struct constructor,
363+ // their types might become ambiguous
364+ Applicability :: MaybeIncorrect
365+ } ;
352366 if has_drop ( cx, cx. typeck_results ( ) . expr_ty ( expr) ) {
353367 None
354368 } else {
355369 let base = match base {
356370 StructTailExpr :: Base ( base) => Some ( base) ,
357371 StructTailExpr :: None | StructTailExpr :: DefaultFields ( _) => None ,
358372 } ;
359- Some ( fields. iter ( ) . map ( |f| & f. expr ) . chain ( base) . map ( Deref :: deref) . collect ( ) )
373+ Some ( (
374+ fields. iter ( ) . map ( |f| & f. expr ) . chain ( base) . map ( Deref :: deref) . collect ( ) ,
375+ applicability,
376+ ) )
360377 }
361378 } ,
362379 ExprKind :: Call ( callee, args) => {
380+ let applicability = if args. iter ( ) . all ( |a| expr_type_is_certain ( cx, a) ) {
381+ Applicability :: MachineApplicable
382+ } else {
383+ // there's a risk that, if we take the args out of the context of the
384+ // call/constructor, their types might become ambiguous
385+ Applicability :: MaybeIncorrect
386+ } ;
363387 if let ExprKind :: Path ( ref qpath) = callee. kind {
364388 if cx. typeck_results ( ) . type_dependent_def ( expr. hir_id ) . is_some ( ) {
365389 // type-dependent function call like `impl FnOnce for X`
@@ -370,7 +394,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
370394 Res :: Def ( DefKind :: Struct | DefKind :: Variant | DefKind :: Ctor ( ..) , ..)
371395 if !has_drop ( cx, cx. typeck_results ( ) . expr_ty ( expr) ) =>
372396 {
373- Some ( args. iter ( ) . collect ( ) )
397+ Some ( ( args. iter ( ) . collect ( ) , applicability ) )
374398 } ,
375399 _ => None ,
376400 }
@@ -383,7 +407,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
383407 block. expr . as_ref ( ) . and_then ( |e| {
384408 match block. rules {
385409 BlockCheckMode :: UnsafeBlock ( UnsafeSource :: UserProvided ) => None ,
386- BlockCheckMode :: DefaultBlock => Some ( vec ! [ & * * e] ) ,
410+ BlockCheckMode :: DefaultBlock => Some ( ( vec ! [ & * * e] , Applicability :: MachineApplicable ) ) ,
387411 // in case of compiler-inserted signaling blocks
388412 BlockCheckMode :: UnsafeBlock ( _) => reduce_expression ( cx, e) ,
389413 }
0 commit comments