blob: c6f54159c7a78acf7f7735b5b4fd300a93696381 [file] [log] [blame] [edit]
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_inside_always_const_context;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, QPath, UnsafeSource};
use rustc_lint::LateContext;
use rustc_span::sym;
use super::USELESS_NONZERO_NEW_UNCHECKED;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, func: &Expr<'tcx>, args: &[Expr<'_>], msrv: Msrv) {
if let ExprKind::Path(QPath::TypeRelative(ty, segment)) = func.kind
&& segment.ident.name == sym::new_unchecked
&& let [init_arg] = args
&& is_inside_always_const_context(cx.tcx, expr.hir_id)
&& cx.typeck_results().node_type(ty.hir_id).is_diag_item(cx, sym::NonZero)
&& msrv.meets(cx, msrvs::CONST_UNWRAP)
{
let mut app = Applicability::MachineApplicable;
let ty_str = snippet_with_applicability(cx, ty.span, "_", &mut app);
let msg = format!("`{ty_str}::new()` and `Option::unwrap()` can be safely used in a `const` context");
let sugg = format!(
"{ty_str}::new({}).unwrap()",
snippet_with_applicability(cx, init_arg.span, "_", &mut app)
);
if let Node::Block(Block {
stmts: [],
span: block_span,
rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
..
}) = cx.tcx.parent_hir_node(expr.hir_id)
{
if !block_span.from_expansion() {
// The expression is the only component of an `unsafe` block. Propose
// to replace the block altogether.
span_lint_and_sugg(
cx,
USELESS_NONZERO_NEW_UNCHECKED,
*block_span,
msg,
"use instead",
sugg,
app,
);
}
} else {
// The expression is enclosed in a larger `unsafe` context. Indicate that
// this may no longer be needed for the fixed expression.
span_lint_and_then(cx, USELESS_NONZERO_NEW_UNCHECKED, expr.span, msg, |diagnostic| {
diagnostic
.span_suggestion(expr.span, "use instead", sugg, app)
.note("the fixed expression does not require an `unsafe` context");
});
}
}
}