@@ -274,7 +274,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
274274 && !stmt. span . in_external_macro ( cx. sess ( ) . source_map ( ) )
275275 && let ctxt = stmt. span . ctxt ( )
276276 && expr. range_span ( ) . unwrap_or ( expr. span ) . ctxt ( ) == ctxt
277- && let Some ( reduced) = reduce_expression ( cx, expr)
277+ && let Some ( ( reduced, applicability ) ) = reduce_expression ( cx, expr)
278278 && reduced. iter ( ) . all ( |e| e. span . ctxt ( ) == ctxt)
279279 {
280280 if let ExprKind :: Index ( ..) = & expr. kind {
@@ -317,48 +317,72 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
317317 stmt. span ,
318318 "unnecessary operation" ,
319319 |diag| {
320- diag. span_suggestion (
321- stmt. span ,
322- "statement can be reduced to" ,
323- snippet,
324- Applicability :: MachineApplicable ,
325- ) ;
320+ diag. span_suggestion ( stmt. span , "statement can be reduced to" , snippet, applicability) ;
326321 } ,
327322 ) ;
328323 }
329324 }
330325}
331326
332- fn reduce_expression < ' a > ( cx : & LateContext < ' _ > , expr : & ' a Expr < ' a > ) -> Option < Vec < & ' a Expr < ' a > > > {
327+ fn reduce_expression < ' a > ( cx : & LateContext < ' _ > , expr : & ' a Expr < ' a > ) -> Option < ( Vec < & ' a Expr < ' a > > , Applicability ) > {
333328 if expr. range_span ( ) . unwrap_or ( expr. span ) . from_expansion ( ) {
334329 return None ;
335330 }
336331 match expr. kind {
337- ExprKind :: Index ( a, b, _) => Some ( vec ! [ a, b] ) ,
332+ ExprKind :: Index ( a, b, _) => Some ( ( vec ! [ a, b] , Applicability :: MachineApplicable ) ) ,
338333 ExprKind :: Binary ( ref binop, a, b) if binop. node != BinOpKind :: And && binop. node != BinOpKind :: Or => {
339- Some ( vec ! [ a, b] )
334+ Some ( ( vec ! [ a, b] , Applicability :: MachineApplicable ) )
340335 } ,
341- ExprKind :: Array ( v) | ExprKind :: Tup ( v) => Some ( v. iter ( ) . collect ( ) ) ,
336+ ExprKind :: Array ( elems) => {
337+ let applicability = if elems. iter ( ) . all ( |elem| expr_type_is_certain ( cx, elem) ) {
338+ Applicability :: MachineApplicable
339+ } else {
340+ // there's a risk that, if we take the elem exprs out of the context of the array,
341+ // their types might become ambiguous
342+ Applicability :: MaybeIncorrect
343+ } ;
344+ Some ( ( elems. iter ( ) . collect ( ) , applicability) )
345+ } ,
346+ ExprKind :: Tup ( v) => Some ( ( v. iter ( ) . collect ( ) , Applicability :: MachineApplicable ) ) ,
342347 ExprKind :: Repeat ( inner, _)
343348 | ExprKind :: Type ( inner, _)
344349 | ExprKind :: Unary ( _, inner)
345350 | ExprKind :: Field ( inner, _)
346- | ExprKind :: AddrOf ( _, _, inner) => reduce_expression ( cx, inner) . or_else ( || Some ( vec ! [ inner] ) ) ,
351+ | ExprKind :: AddrOf ( _, _, inner) => {
352+ reduce_expression ( cx, inner) . or_else ( || Some ( ( vec ! [ inner] , Applicability :: MachineApplicable ) ) )
353+ } ,
347354 ExprKind :: Cast ( inner, _) if expr_type_is_certain ( cx, inner) => {
348- reduce_expression ( cx, inner) . or_else ( || Some ( vec ! [ inner] ) )
355+ reduce_expression ( cx, inner) . or_else ( || Some ( ( vec ! [ inner] , Applicability :: MachineApplicable ) ) )
349356 } ,
350357 ExprKind :: Struct ( _, fields, ref base) => {
358+ let applicability = if fields. iter ( ) . all ( |f| expr_type_is_certain ( cx, f. expr ) ) {
359+ Applicability :: MachineApplicable
360+ } else {
361+ // there's a risk that, if we take the field exprs out of the context of the struct constructor,
362+ // their types might become ambiguous
363+ Applicability :: MaybeIncorrect
364+ } ;
351365 if has_drop ( cx, cx. typeck_results ( ) . expr_ty ( expr) ) {
352366 None
353367 } else {
354368 let base = match base {
355369 StructTailExpr :: Base ( base) => Some ( base) ,
356370 StructTailExpr :: None | StructTailExpr :: DefaultFields ( _) => None ,
357371 } ;
358- Some ( fields. iter ( ) . map ( |f| & f. expr ) . chain ( base) . map ( Deref :: deref) . collect ( ) )
372+ Some ( (
373+ fields. iter ( ) . map ( |f| & f. expr ) . chain ( base) . map ( Deref :: deref) . collect ( ) ,
374+ applicability,
375+ ) )
359376 }
360377 } ,
361378 ExprKind :: Call ( callee, args) => {
379+ let applicability = if args. iter ( ) . all ( |a| expr_type_is_certain ( cx, a) ) {
380+ Applicability :: MachineApplicable
381+ } else {
382+ // there's a risk that, if we take the args out of the context of the
383+ // call/constructor, their types might become ambiguous
384+ Applicability :: MaybeIncorrect
385+ } ;
362386 if let ExprKind :: Path ( ref qpath) = callee. kind {
363387 if cx. typeck_results ( ) . type_dependent_def ( expr. hir_id ) . is_some ( ) {
364388 // type-dependent function call like `impl FnOnce for X`
@@ -369,7 +393,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
369393 Res :: Def ( DefKind :: Struct | DefKind :: Variant | DefKind :: Ctor ( ..) , ..)
370394 if !has_drop ( cx, cx. typeck_results ( ) . expr_ty ( expr) ) =>
371395 {
372- Some ( args. iter ( ) . collect ( ) )
396+ Some ( ( args. iter ( ) . collect ( ) , applicability ) )
373397 } ,
374398 _ => None ,
375399 }
@@ -382,7 +406,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
382406 block. expr . as_ref ( ) . and_then ( |e| {
383407 match block. rules {
384408 BlockCheckMode :: UnsafeBlock ( UnsafeSource :: UserProvided ) => None ,
385- BlockCheckMode :: DefaultBlock => Some ( vec ! [ & * * e] ) ,
409+ BlockCheckMode :: DefaultBlock => Some ( ( vec ! [ & * * e] , Applicability :: MachineApplicable ) ) ,
386410 // in case of compiler-inserted signaling blocks
387411 BlockCheckMode :: UnsafeBlock ( _) => reduce_expression ( cx, e) ,
388412 }
0 commit comments