11use clippy_utils:: diagnostics:: span_lint_hir_and_then;
2- use clippy_utils:: numeric_literal;
32use clippy_utils:: source:: snippet_opt;
3+ use clippy_utils:: { get_parent_node, numeric_literal} ;
44use if_chain:: if_chain;
55use rustc_ast:: ast:: { LitFloatType , LitIntType , LitKind } ;
66use rustc_errors:: Applicability ;
77use rustc_hir:: {
88 intravisit:: { walk_expr, walk_stmt, Visitor } ,
9- Body , Expr , ExprKind , HirId , Lit , Stmt , StmtKind ,
9+ Body , Expr , ExprKind , HirId , ItemKind , Lit , Node , Stmt , StmtKind ,
1010} ;
1111use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1212use rustc_middle:: {
@@ -55,22 +55,31 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
5555
5656impl < ' tcx > LateLintPass < ' tcx > for DefaultNumericFallback {
5757 fn check_body ( & mut self , cx : & LateContext < ' tcx > , body : & ' tcx Body < ' _ > ) {
58- let mut visitor = NumericFallbackVisitor :: new ( cx) ;
58+ let is_parent_const = if let Some ( Node :: Item ( item) ) = get_parent_node ( cx. tcx , body. id ( ) . hir_id ) {
59+ matches ! ( item. kind, ItemKind :: Const ( ..) )
60+ } else {
61+ false
62+ } ;
63+ let mut visitor = NumericFallbackVisitor :: new ( cx, is_parent_const) ;
5964 visitor. visit_body ( body) ;
6065 }
6166}
6267
6368struct NumericFallbackVisitor < ' a , ' tcx > {
6469 /// Stack manages type bound of exprs. The top element holds current expr type.
65- ty_bounds : Vec < TyBound < ' tcx > > ,
70+ ty_bounds : Vec < ExplicitTyBound > ,
6671
6772 cx : & ' a LateContext < ' tcx > ,
6873}
6974
7075impl < ' a , ' tcx > NumericFallbackVisitor < ' a , ' tcx > {
71- fn new ( cx : & ' a LateContext < ' tcx > ) -> Self {
76+ fn new ( cx : & ' a LateContext < ' tcx > , is_parent_const : bool ) -> Self {
7277 Self {
73- ty_bounds : vec ! [ TyBound :: Nothing ] ,
78+ ty_bounds : vec ! [ if is_parent_const {
79+ ExplicitTyBound ( true )
80+ } else {
81+ ExplicitTyBound ( false )
82+ } ] ,
7483 cx,
7584 }
7685 }
@@ -79,10 +88,9 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
7988 fn check_lit ( & self , lit : & Lit , lit_ty : Ty < ' tcx > , emit_hir_id : HirId ) {
8089 if_chain ! {
8190 if !in_external_macro( self . cx. sess( ) , lit. span) ;
82- if let Some ( ty_bound ) = self . ty_bounds. last( ) ;
91+ if matches! ( self . ty_bounds. last( ) , Some ( ExplicitTyBound ( false ) ) ) ;
8392 if matches!( lit. node,
8493 LitKind :: Int ( _, LitIntType :: Unsuffixed ) | LitKind :: Float ( _, LitFloatType :: Unsuffixed ) ) ;
85- if !ty_bound. is_numeric( ) ;
8694 then {
8795 let ( suffix, is_float) = match lit_ty. kind( ) {
8896 ty:: Int ( IntTy :: I32 ) => ( "i32" , false ) ,
@@ -123,7 +131,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
123131 if let Some ( fn_sig) = fn_sig_opt ( self . cx , func. hir_id ) {
124132 for ( expr, bound) in iter:: zip ( * args, fn_sig. skip_binder ( ) . inputs ( ) ) {
125133 // Push found arg type, then visit arg.
126- self . ty_bounds . push ( TyBound :: Ty ( * bound) ) ;
134+ self . ty_bounds . push ( ( * bound) . into ( ) ) ;
127135 self . visit_expr ( expr) ;
128136 self . ty_bounds . pop ( ) ;
129137 }
@@ -135,7 +143,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
135143 if let Some ( def_id) = self . cx . typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) {
136144 let fn_sig = self . cx . tcx . fn_sig ( def_id) . skip_binder ( ) ;
137145 for ( expr, bound) in iter:: zip ( std:: iter:: once ( * receiver) . chain ( args. iter ( ) ) , fn_sig. inputs ( ) ) {
138- self . ty_bounds . push ( TyBound :: Ty ( * bound) ) ;
146+ self . ty_bounds . push ( ( * bound) . into ( ) ) ;
139147 self . visit_expr ( expr) ;
140148 self . ty_bounds . pop ( ) ;
141149 }
@@ -169,7 +177,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
169177
170178 // Visit base with no bound.
171179 if let Some ( base) = base {
172- self . ty_bounds. push( TyBound :: Nothing ) ;
180+ self . ty_bounds. push( ExplicitTyBound ( false ) ) ;
173181 self . visit_expr( base) ;
174182 self . ty_bounds. pop( ) ;
175183 }
@@ -192,15 +200,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
192200
193201 fn visit_stmt ( & mut self , stmt : & ' tcx Stmt < ' _ > ) {
194202 match stmt. kind {
195- StmtKind :: Local ( local) => {
196- if local. ty . is_some ( ) {
197- self . ty_bounds . push ( TyBound :: Any ) ;
198- } else {
199- self . ty_bounds . push ( TyBound :: Nothing ) ;
200- }
201- } ,
203+ // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
204+ StmtKind :: Local ( local) => self . ty_bounds . push ( ExplicitTyBound ( local. ty . is_some ( ) ) ) ,
202205
203- _ => self . ty_bounds . push ( TyBound :: Nothing ) ,
206+ _ => self . ty_bounds . push ( ExplicitTyBound ( false ) ) ,
204207 }
205208
206209 walk_stmt ( self , stmt) ;
@@ -218,28 +221,18 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
218221 }
219222}
220223
224+ /// Wrapper around a `bool` to make the meaning of the value clearer
221225#[ derive( Debug , Clone , Copy ) ]
222- enum TyBound < ' tcx > {
223- Any ,
224- Ty ( Ty < ' tcx > ) ,
225- Nothing ,
226- }
226+ struct ExplicitTyBound ( pub bool ) ;
227227
228- impl < ' tcx > TyBound < ' tcx > {
229- fn is_numeric ( self ) -> bool {
230- match self {
231- TyBound :: Any => true ,
232- TyBound :: Ty ( t) => t. is_numeric ( ) ,
233- TyBound :: Nothing => false ,
234- }
228+ impl < ' tcx > From < Ty < ' tcx > > for ExplicitTyBound {
229+ fn from ( v : Ty < ' tcx > ) -> Self {
230+ Self ( v. is_numeric ( ) )
235231 }
236232}
237233
238- impl < ' tcx > From < Option < Ty < ' tcx > > > for TyBound < ' tcx > {
234+ impl < ' tcx > From < Option < Ty < ' tcx > > > for ExplicitTyBound {
239235 fn from ( v : Option < Ty < ' tcx > > ) -> Self {
240- match v {
241- Some ( t) => TyBound :: Ty ( t) ,
242- None => TyBound :: Nothing ,
243- }
236+ Self ( v. map_or ( false , Ty :: is_numeric) )
244237 }
245238}
0 commit comments