4
4
//! overview of how lints are implemented.
5
5
6
6
use std:: cell:: Cell ;
7
+ use std:: ops:: ControlFlow ;
7
8
use std:: slice;
8
9
10
+ use rustc_ast:: BindingMode ;
9
11
use rustc_data_structures:: fx:: FxIndexMap ;
10
12
use rustc_data_structures:: sync;
11
13
use rustc_data_structures:: unord:: UnordMap ;
@@ -14,6 +16,8 @@ use rustc_feature::Features;
14
16
use rustc_hir:: def:: Res ;
15
17
use rustc_hir:: def_id:: { CrateNum , DefId } ;
16
18
use rustc_hir:: definitions:: { DefPathData , DisambiguatedDefPathData } ;
19
+ use rustc_hir:: intravisit:: Visitor ;
20
+ use rustc_hir:: { HirId , Pat , PatKind } ;
17
21
use rustc_middle:: bug;
18
22
use rustc_middle:: middle:: privacy:: EffectiveVisibilities ;
19
23
use rustc_middle:: ty:: layout:: { LayoutError , LayoutOfHelpers , TyAndLayout } ;
@@ -890,7 +894,18 @@ impl<'tcx> LateContext<'tcx> {
890
894
}
891
895
&& let Some ( init) = match parent_node {
892
896
hir:: Node :: Expr ( expr) => Some ( expr) ,
893
- hir:: Node :: LetStmt ( hir:: LetStmt { init, .. } ) => * init,
897
+ hir:: Node :: LetStmt ( hir:: LetStmt {
898
+ init,
899
+ // Bindigng is immutable, init cannot be re-assigned
900
+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: NONE , ..) , .. } ,
901
+ ..
902
+ } ) => * init,
903
+ hir:: Node :: LetStmt ( hir:: LetStmt {
904
+ init,
905
+ // Bindigng is mutable, init can be re-assigned to, if it is bail-out
906
+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: MUT , binding_id, ..) , .. } ,
907
+ ..
908
+ } ) if !ReassignBindingFinder :: is_binding_reassigned ( self , * binding_id) => * init,
894
909
_ => None ,
895
910
}
896
911
{
@@ -935,7 +950,18 @@ impl<'tcx> LateContext<'tcx> {
935
950
}
936
951
&& let Some ( init) = match parent_node {
937
952
hir:: Node :: Expr ( expr) => Some ( expr) ,
938
- hir:: Node :: LetStmt ( hir:: LetStmt { init, .. } ) => * init,
953
+ hir:: Node :: LetStmt ( hir:: LetStmt {
954
+ init,
955
+ // Bindigng is immutable, init cannot be re-assigned
956
+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: NONE , ..) , .. } ,
957
+ ..
958
+ } ) => * init,
959
+ hir:: Node :: LetStmt ( hir:: LetStmt {
960
+ init,
961
+ // Bindigng is mutable, init can be re-assigned to, if it is bail-out
962
+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: MUT , binding_id, ..) , .. } ,
963
+ ..
964
+ } ) if !ReassignBindingFinder :: is_binding_reassigned ( self , * binding_id) => * init,
939
965
hir:: Node :: Item ( item) => match item. kind {
940
966
hir:: ItemKind :: Const ( .., body_id) | hir:: ItemKind :: Static ( .., body_id) => {
941
967
Some ( self . tcx . hir_body ( body_id) . value )
@@ -980,3 +1006,40 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
980
1006
err
981
1007
}
982
1008
}
1009
+
1010
+ struct ReassignBindingFinder < ' a , ' tcx > {
1011
+ cx : & ' a LateContext < ' tcx > ,
1012
+ binding_id : HirId ,
1013
+ }
1014
+
1015
+ impl < ' a , ' tcx > ReassignBindingFinder < ' a , ' tcx > {
1016
+ fn is_binding_reassigned ( cx : & ' a LateContext < ' tcx > , binding_id : HirId ) -> bool {
1017
+ if let Some ( enclosing_scope_id) = cx. tcx . hir_get_enclosing_scope ( binding_id)
1018
+ && let hir:: Node :: Block ( block) = cx. tcx . hir_node ( enclosing_scope_id)
1019
+ {
1020
+ let mut finder = ReassignBindingFinder { cx, binding_id } ;
1021
+ finder. visit_block ( block) . is_break ( )
1022
+ } else {
1023
+ false
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ impl < ' tcx > Visitor < ' tcx > for ReassignBindingFinder < ' _ , ' tcx > {
1029
+ type Result = ControlFlow < ( ) > ;
1030
+ type NestedFilter = rustc_middle:: hir:: nested_filter:: OnlyBodies ;
1031
+
1032
+ fn visit_path ( & mut self , path : & hir:: Path < ' tcx > , hir_id : HirId ) -> Self :: Result {
1033
+ if let Res :: Local ( id) = path. res {
1034
+ if self . binding_id == id && self . cx . tcx . hir_is_lhs ( hir_id) {
1035
+ return ControlFlow :: Break ( ( ) ) ;
1036
+ }
1037
+ }
1038
+
1039
+ ControlFlow :: Continue ( ( ) )
1040
+ }
1041
+
1042
+ fn maybe_tcx ( & mut self ) -> Self :: MaybeTyCtxt {
1043
+ self . cx . tcx
1044
+ }
1045
+ }
0 commit comments