blob: 4691ee02d9539b759485ec15d26aaa04b92b0922 [file] [edit]
use super::FOR_UNBOUNDED_RANGE;
use super::infinite_loop::LoopVisitor;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
use rustc_ast::Label;
use rustc_hir::Expr;
use rustc_hir::intravisit::Visitor as _;
use rustc_lint::LateContext;
use rustc_span::Span;
pub fn check<'tcx>(
cx: &LateContext<'tcx>,
label: Option<Label>,
arg: &'tcx Expr<'tcx>,
span: Span,
body: &'tcx Expr<'tcx>,
) {
if let Some(range) = higher::Range::hir(cx, arg)
&& let Some(range_start) = range.start
&& let None = range.end
&& let ty = cx.typeck_results().expr_ty_adjusted(range_start)
&& (ty.is_integral() || ty.is_char())
{
let mut loop_visitor = LoopVisitor::new(cx, label);
loop_visitor.visit_expr(body);
if loop_visitor.is_finite {
// The loop is likely finite.
return;
}
span_lint_and_then(cx, FOR_UNBOUNDED_RANGE, span, "for loop on unbounded range", |diag| {
diag.span_suggestion_verbose(
arg.span.shrink_to_hi(),
"for loops over unbounded ranges will wrap around and may panic, consider adding an inclusive high bound",
format!("={ty}::MAX"),
rustc_errors::Applicability::MaybeIncorrect,
);
});
}
}