Skip to content

Commit 5ec2f5e

Browse files
committed
Suggest using an inclusive range for an overflowing endpoint
1 parent 2cefd99 commit 5ec2f5e

File tree

1 file changed

+61
-15
lines changed

1 file changed

+61
-15
lines changed

src/librustc_lint/types.rs

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![allow(non_snake_case)]
22

3-
use rustc::hir::Node;
3+
use rustc::hir::{ExprKind, Node};
4+
use rustc::hir::lowering::is_range_literal;
45
use rustc::ty::subst::SubstsRef;
56
use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
67
use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx};
@@ -129,21 +130,66 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
129130
if lit_val < min || lit_val > max {
130131
let parent_id = cx.tcx.hir().get_parent_node_by_hir_id(e.hir_id);
131132
if let Node::Expr(parent_expr) = cx.tcx.hir().get_by_hir_id(parent_id) {
132-
if let hir::ExprKind::Cast(..) = parent_expr.node {
133-
if let ty::Char = cx.tables.expr_ty(parent_expr).sty {
134-
let mut err = cx.struct_span_lint(
135-
OVERFLOWING_LITERALS,
136-
parent_expr.span,
137-
"only u8 can be cast into char");
138-
err.span_suggestion(
139-
parent_expr.span,
140-
&"use a char literal instead",
141-
format!("'\\u{{{:X}}}'", lit_val),
142-
Applicability::MachineApplicable
143-
);
144-
err.emit();
145-
return
133+
match parent_expr.node {
134+
hir::ExprKind::Cast(..) => {
135+
if let ty::Char = cx.tables.expr_ty(parent_expr).sty {
136+
let mut err = cx.struct_span_lint(
137+
OVERFLOWING_LITERALS,
138+
parent_expr.span,
139+
"only u8 can be cast into char",
140+
);
141+
err.span_suggestion(
142+
parent_expr.span,
143+
&"use a char literal instead",
144+
format!("'\\u{{{:X}}}'", lit_val),
145+
Applicability::MachineApplicable,
146+
);
147+
err.emit();
148+
return;
149+
}
150+
}
151+
hir::ExprKind::Struct(..)
152+
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+
let suggestion = format!(
176+
"{}..={}",
177+
start,
178+
lit_val - 1,
179+
);
180+
err.span_suggestion(
181+
parent_expr.span,
182+
&"use an inclusive range instead",
183+
suggestion,
184+
Applicability::MachineApplicable,
185+
);
186+
err.emit();
187+
return;
188+
}
189+
}
190+
}
146191
}
192+
_ => {}
147193
}
148194
}
149195
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {

0 commit comments

Comments
 (0)