@@ -58,6 +58,61 @@ impl TypeLimits {
58
58
}
59
59
}
60
60
61
+ /// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint.
62
+ /// Returns `true` iff the lint was overridden.
63
+ fn lint_overflowing_range_endpoint < ' a , ' tcx > (
64
+ cx : & LateContext < ' a , ' tcx > ,
65
+ lit : & ast:: Lit ,
66
+ lit_val : u128 ,
67
+ max : u128 ,
68
+ expr : & ' tcx hir:: Expr ,
69
+ parent_expr : & ' tcx hir:: Expr ,
70
+ ty : impl std:: fmt:: Debug ,
71
+ ) -> bool {
72
+ // We only want to handle exclusive (`..`) ranges,
73
+ // which are represented as `ExprKind::Struct`.
74
+ if let ExprKind :: Struct ( _, eps, _) = & parent_expr. node {
75
+ debug_assert_eq ! ( eps. len( ) , 2 ) ;
76
+ // We can suggest using an inclusive range
77
+ // (`..=`) instead only if it is the `end` that is
78
+ // overflowing and only by 1.
79
+ if eps[ 1 ] . expr . hir_id == expr. hir_id && lit_val - 1 == max {
80
+ let mut err = cx. struct_span_lint (
81
+ OVERFLOWING_LITERALS ,
82
+ parent_expr. span ,
83
+ & format ! ( "range endpoint is out of range for `{:?}`" , ty) ,
84
+ ) ;
85
+ if let Ok ( start) = cx. sess ( ) . source_map ( ) . span_to_snippet ( eps[ 0 ] . span ) {
86
+ use ast:: { LitKind , LitIntType } ;
87
+ // We need to preserve the literal's suffix,
88
+ // as it may determine typing information.
89
+ let suffix = match lit. node {
90
+ LitKind :: Int ( _, LitIntType :: Signed ( s) ) => format ! ( "{}" , s) ,
91
+ LitKind :: Int ( _, LitIntType :: Unsigned ( s) ) => format ! ( "{}" , s) ,
92
+ LitKind :: Int ( _, LitIntType :: Unsuffixed ) => "" . to_owned ( ) ,
93
+ _ => bug ! ( ) ,
94
+ } ;
95
+ let suggestion = format ! (
96
+ "{}..={}{}" ,
97
+ start,
98
+ lit_val - 1 ,
99
+ suffix,
100
+ ) ;
101
+ err. span_suggestion (
102
+ parent_expr. span ,
103
+ & "use an inclusive range instead" ,
104
+ suggestion,
105
+ Applicability :: MachineApplicable ,
106
+ ) ;
107
+ err. emit ( ) ;
108
+ return true ;
109
+ }
110
+ }
111
+ }
112
+
113
+ false
114
+ }
115
+
61
116
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for TypeLimits {
62
117
fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , e : & ' tcx hir:: Expr ) {
63
118
match e. node {
@@ -103,6 +158,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
103
158
) ;
104
159
return ;
105
160
}
161
+
162
+ let par_id = cx. tcx . hir ( ) . get_parent_node_by_hir_id ( e. hir_id ) ;
163
+ if let Node :: Expr ( par_e) = cx. tcx . hir ( ) . get_by_hir_id ( par_id) {
164
+ if let hir:: ExprKind :: Struct ( ..) = par_e. node {
165
+ if is_range_literal ( cx. sess ( ) , par_e)
166
+ && lint_overflowing_range_endpoint (
167
+ cx,
168
+ lit,
169
+ v,
170
+ max,
171
+ e,
172
+ par_e,
173
+ t,
174
+ )
175
+ {
176
+ // The overflowing literal lint was overridden.
177
+ return ;
178
+ }
179
+ }
180
+ }
181
+
106
182
cx. span_lint (
107
183
OVERFLOWING_LITERALS ,
108
184
e. span ,
@@ -150,61 +226,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
150
226
}
151
227
hir:: ExprKind :: Struct ( ..)
152
228
if is_range_literal ( cx. sess ( ) , parent_expr) => {
153
- // We only want to handle exclusive (`..`) ranges,
154
- // which are represented as `ExprKind::Struct`.
155
- if let ExprKind :: Struct ( _, eps, _) = & parent_expr. node {
156
- debug_assert_eq ! ( eps. len( ) , 2 ) ;
157
- // We can suggest using an inclusive range
158
- // (`..=`) instead only if it is the `end` that is
159
- // overflowing and only by 1.
160
- if eps[ 1 ] . expr . hir_id == e. hir_id
161
- && lit_val - 1 == max
162
- {
163
- let mut err = cx. struct_span_lint (
164
- OVERFLOWING_LITERALS ,
165
- parent_expr. span ,
166
- & format ! (
167
- "range endpoint is out of range \
168
- for `{:?}`",
169
- t,
170
- ) ,
171
- ) ;
172
- if let Ok ( start) = cx. sess ( ) . source_map ( )
173
- . span_to_snippet ( eps[ 0 ] . span )
174
- {
175
- use ast:: { LitKind :: * , LitIntType } ;
176
- // We need to preserve the literal's suffix,
177
- // as it may determine typing information.
178
- let suffix = match lit. node {
179
- Int ( _, LitIntType :: Signed ( s) ) => {
180
- format ! ( "{}" , s)
181
- }
182
- Int ( _, LitIntType :: Unsigned ( s) ) => {
183
- format ! ( "{}" , s)
184
- }
185
- Int ( _, LitIntType :: Unsuffixed ) => {
186
- "" . to_owned ( )
187
- }
188
- _ => bug ! ( ) ,
189
- } ;
190
- let suggestion = format ! (
191
- "{}..={}{}" ,
192
- start,
193
- lit_val - 1 ,
194
- suffix,
195
- ) ;
196
- err. span_suggestion (
197
- parent_expr. span ,
198
- & "use an inclusive range instead" ,
199
- suggestion,
200
- Applicability :: MachineApplicable ,
201
- ) ;
202
- err. emit ( ) ;
203
- return ;
204
- }
205
- }
229
+ if lint_overflowing_range_endpoint (
230
+ cx,
231
+ lit,
232
+ lit_val,
233
+ max,
234
+ e,
235
+ parent_expr,
236
+ t,
237
+ ) {
238
+ // The overflowing literal lint was overridden.
239
+ return ;
206
240
}
207
- }
241
+ }
208
242
_ => { }
209
243
}
210
244
}
0 commit comments