@@ -8,6 +8,7 @@ mod infinite_loop;
8
8
mod manual_flatten;
9
9
mod manual_memcpy;
10
10
mod needless_collect;
11
+ mod never_loop;
11
12
mod same_item_push;
12
13
mod utils;
13
14
@@ -16,21 +17,18 @@ use crate::utils::usage::mutated_variables;
16
17
use crate :: utils:: {
17
18
get_enclosing_block, get_trait_def_id, higher, implements_trait, is_in_panic_handler, is_no_std_crate,
18
19
is_refutable, last_path_segment, match_trait_method, path_to_local, path_to_local_id, paths,
19
- snippet_with_applicability, span_lint , span_lint_and_help, span_lint_and_sugg, sugg,
20
+ snippet_with_applicability, span_lint_and_help, span_lint_and_sugg, sugg,
20
21
} ;
21
22
use if_chain:: if_chain;
22
23
use rustc_errors:: Applicability ;
23
24
use rustc_hir:: intravisit:: { walk_block, walk_expr, NestedVisitorMap , Visitor } ;
24
- use rustc_hir:: {
25
- Block , Expr , ExprKind , HirId , InlineAsmOperand , LoopSource , MatchSource , Node , Pat , PatKind , Stmt , StmtKind ,
26
- } ;
25
+ use rustc_hir:: { Block , Expr , ExprKind , HirId , LoopSource , MatchSource , Node , Pat , PatKind , StmtKind } ;
27
26
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
28
27
use rustc_middle:: hir:: map:: Map ;
29
28
use rustc_middle:: lint:: in_external_macro;
30
29
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
31
30
use rustc_span:: source_map:: Span ;
32
31
use rustc_span:: symbol:: sym;
33
- use std:: iter:: { once, Iterator } ;
34
32
use utils:: {
35
33
get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor , InitializeVisitor , LoopNestVisitor , Nesting ,
36
34
} ;
@@ -567,12 +565,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
567
565
}
568
566
569
567
// check for never_loop
570
- if let ExprKind :: Loop ( ref block, _, _, _) = expr. kind {
571
- match never_loop_block ( block, expr. hir_id ) {
572
- NeverLoopResult :: AlwaysBreak => span_lint ( cx, NEVER_LOOP , expr. span , "this loop never actually loops" ) ,
573
- NeverLoopResult :: MayContinueMainLoop | NeverLoopResult :: Otherwise => ( ) ,
574
- }
575
- }
568
+ never_loop:: check_never_loop ( cx, expr) ;
576
569
577
570
// check for `loop { if let {} else break }` that could be `while let`
578
571
// (also matches an explicit "match" instead of "if let")
@@ -689,164 +682,6 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
689
682
}
690
683
}
691
684
692
- enum NeverLoopResult {
693
- // A break/return always get triggered but not necessarily for the main loop.
694
- AlwaysBreak ,
695
- // A continue may occur for the main loop.
696
- MayContinueMainLoop ,
697
- Otherwise ,
698
- }
699
-
700
- #[ must_use]
701
- fn absorb_break ( arg : & NeverLoopResult ) -> NeverLoopResult {
702
- match * arg {
703
- NeverLoopResult :: AlwaysBreak | NeverLoopResult :: Otherwise => NeverLoopResult :: Otherwise ,
704
- NeverLoopResult :: MayContinueMainLoop => NeverLoopResult :: MayContinueMainLoop ,
705
- }
706
- }
707
-
708
- // Combine two results for parts that are called in order.
709
- #[ must_use]
710
- fn combine_seq ( first : NeverLoopResult , second : NeverLoopResult ) -> NeverLoopResult {
711
- match first {
712
- NeverLoopResult :: AlwaysBreak | NeverLoopResult :: MayContinueMainLoop => first,
713
- NeverLoopResult :: Otherwise => second,
714
- }
715
- }
716
-
717
- // Combine two results where both parts are called but not necessarily in order.
718
- #[ must_use]
719
- fn combine_both ( left : NeverLoopResult , right : NeverLoopResult ) -> NeverLoopResult {
720
- match ( left, right) {
721
- ( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
722
- NeverLoopResult :: MayContinueMainLoop
723
- } ,
724
- ( NeverLoopResult :: AlwaysBreak , _) | ( _, NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
725
- ( NeverLoopResult :: Otherwise , NeverLoopResult :: Otherwise ) => NeverLoopResult :: Otherwise ,
726
- }
727
- }
728
-
729
- // Combine two results where only one of the part may have been executed.
730
- #[ must_use]
731
- fn combine_branches ( b1 : NeverLoopResult , b2 : NeverLoopResult ) -> NeverLoopResult {
732
- match ( b1, b2) {
733
- ( NeverLoopResult :: AlwaysBreak , NeverLoopResult :: AlwaysBreak ) => NeverLoopResult :: AlwaysBreak ,
734
- ( NeverLoopResult :: MayContinueMainLoop , _) | ( _, NeverLoopResult :: MayContinueMainLoop ) => {
735
- NeverLoopResult :: MayContinueMainLoop
736
- } ,
737
- ( NeverLoopResult :: Otherwise , _) | ( _, NeverLoopResult :: Otherwise ) => NeverLoopResult :: Otherwise ,
738
- }
739
- }
740
-
741
- fn never_loop_block ( block : & Block < ' _ > , main_loop_id : HirId ) -> NeverLoopResult {
742
- let stmts = block. stmts . iter ( ) . map ( stmt_to_expr) ;
743
- let expr = once ( block. expr . as_deref ( ) ) ;
744
- let mut iter = stmts. chain ( expr) . flatten ( ) ;
745
- never_loop_expr_seq ( & mut iter, main_loop_id)
746
- }
747
-
748
- fn stmt_to_expr < ' tcx > ( stmt : & Stmt < ' tcx > ) -> Option < & ' tcx Expr < ' tcx > > {
749
- match stmt. kind {
750
- StmtKind :: Semi ( ref e, ..) | StmtKind :: Expr ( ref e, ..) => Some ( e) ,
751
- StmtKind :: Local ( ref local) => local. init . as_deref ( ) ,
752
- _ => None ,
753
- }
754
- }
755
-
756
- fn never_loop_expr ( expr : & Expr < ' _ > , main_loop_id : HirId ) -> NeverLoopResult {
757
- match expr. kind {
758
- ExprKind :: Box ( ref e)
759
- | ExprKind :: Unary ( _, ref e)
760
- | ExprKind :: Cast ( ref e, _)
761
- | ExprKind :: Type ( ref e, _)
762
- | ExprKind :: Field ( ref e, _)
763
- | ExprKind :: AddrOf ( _, _, ref e)
764
- | ExprKind :: Struct ( _, _, Some ( ref e) )
765
- | ExprKind :: Repeat ( ref e, _)
766
- | ExprKind :: DropTemps ( ref e) => never_loop_expr ( e, main_loop_id) ,
767
- ExprKind :: Array ( ref es) | ExprKind :: MethodCall ( _, _, ref es, _) | ExprKind :: Tup ( ref es) => {
768
- never_loop_expr_all ( & mut es. iter ( ) , main_loop_id)
769
- } ,
770
- ExprKind :: Call ( ref e, ref es) => never_loop_expr_all ( & mut once ( & * * e) . chain ( es. iter ( ) ) , main_loop_id) ,
771
- ExprKind :: Binary ( _, ref e1, ref e2)
772
- | ExprKind :: Assign ( ref e1, ref e2, _)
773
- | ExprKind :: AssignOp ( _, ref e1, ref e2)
774
- | ExprKind :: Index ( ref e1, ref e2) => never_loop_expr_all ( & mut [ & * * e1, & * * e2] . iter ( ) . cloned ( ) , main_loop_id) ,
775
- ExprKind :: Loop ( ref b, _, _, _) => {
776
- // Break can come from the inner loop so remove them.
777
- absorb_break ( & never_loop_block ( b, main_loop_id) )
778
- } ,
779
- ExprKind :: If ( ref e, ref e2, ref e3) => {
780
- let e1 = never_loop_expr ( e, main_loop_id) ;
781
- let e2 = never_loop_expr ( e2, main_loop_id) ;
782
- let e3 = e3
783
- . as_ref ( )
784
- . map_or ( NeverLoopResult :: Otherwise , |e| never_loop_expr ( e, main_loop_id) ) ;
785
- combine_seq ( e1, combine_branches ( e2, e3) )
786
- } ,
787
- ExprKind :: Match ( ref e, ref arms, _) => {
788
- let e = never_loop_expr ( e, main_loop_id) ;
789
- if arms. is_empty ( ) {
790
- e
791
- } else {
792
- let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| & * a. body ) , main_loop_id) ;
793
- combine_seq ( e, arms)
794
- }
795
- } ,
796
- ExprKind :: Block ( ref b, _) => never_loop_block ( b, main_loop_id) ,
797
- ExprKind :: Continue ( d) => {
798
- let id = d
799
- . target_id
800
- . expect ( "target ID can only be missing in the presence of compilation errors" ) ;
801
- if id == main_loop_id {
802
- NeverLoopResult :: MayContinueMainLoop
803
- } else {
804
- NeverLoopResult :: AlwaysBreak
805
- }
806
- } ,
807
- ExprKind :: Break ( _, ref e) | ExprKind :: Ret ( ref e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
808
- combine_seq ( never_loop_expr ( e, main_loop_id) , NeverLoopResult :: AlwaysBreak )
809
- } ) ,
810
- ExprKind :: InlineAsm ( ref asm) => asm
811
- . operands
812
- . iter ( )
813
- . map ( |( o, _) | match o {
814
- InlineAsmOperand :: In { expr, .. }
815
- | InlineAsmOperand :: InOut { expr, .. }
816
- | InlineAsmOperand :: Const { expr }
817
- | InlineAsmOperand :: Sym { expr } => never_loop_expr ( expr, main_loop_id) ,
818
- InlineAsmOperand :: Out { expr, .. } => never_loop_expr_all ( & mut expr. iter ( ) , main_loop_id) ,
819
- InlineAsmOperand :: SplitInOut { in_expr, out_expr, .. } => {
820
- never_loop_expr_all ( & mut once ( in_expr) . chain ( out_expr. iter ( ) ) , main_loop_id)
821
- } ,
822
- } )
823
- . fold ( NeverLoopResult :: Otherwise , combine_both) ,
824
- ExprKind :: Struct ( _, _, None )
825
- | ExprKind :: Yield ( _, _)
826
- | ExprKind :: Closure ( _, _, _, _, _)
827
- | ExprKind :: LlvmInlineAsm ( _)
828
- | ExprKind :: Path ( _)
829
- | ExprKind :: ConstBlock ( _)
830
- | ExprKind :: Lit ( _)
831
- | ExprKind :: Err => NeverLoopResult :: Otherwise ,
832
- }
833
- }
834
-
835
- fn never_loop_expr_seq < ' a , T : Iterator < Item = & ' a Expr < ' a > > > ( es : & mut T , main_loop_id : HirId ) -> NeverLoopResult {
836
- es. map ( |e| never_loop_expr ( e, main_loop_id) )
837
- . fold ( NeverLoopResult :: Otherwise , combine_seq)
838
- }
839
-
840
- fn never_loop_expr_all < ' a , T : Iterator < Item = & ' a Expr < ' a > > > ( es : & mut T , main_loop_id : HirId ) -> NeverLoopResult {
841
- es. map ( |e| never_loop_expr ( e, main_loop_id) )
842
- . fold ( NeverLoopResult :: Otherwise , combine_both)
843
- }
844
-
845
- fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr < ' a > > > ( e : & mut T , main_loop_id : HirId ) -> NeverLoopResult {
846
- e. map ( |e| never_loop_expr ( e, main_loop_id) )
847
- . fold ( NeverLoopResult :: AlwaysBreak , combine_branches)
848
- }
849
-
850
685
fn check_for_loop < ' tcx > (
851
686
cx : & LateContext < ' tcx > ,
852
687
pat : & ' tcx Pat < ' _ > ,
0 commit comments