Use ConstArg for array lengths

This commit is contained in:
Noah Lev 2024-06-04 18:24:08 -07:00
parent 620a056a33
commit 6e99e2d748
5 changed files with 42 additions and 24 deletions

View File

@ -106,13 +106,12 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
///
/// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the
/// correct result.
fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else {
fn repeat_expr_might_be_expanded<'tcx>(expr: &Expr<'tcx>) -> bool {
let ExprKind::Repeat(_, ArrayLen::Body(len_ct)) = expr.kind else {
return false;
};
let len_span = cx.tcx.def_span(anon_const.def_id);
!expr.span.contains(len_span)
!expr.span.contains(len_ct.span())
}
expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(cx, expr)
expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(expr)
}

View File

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::has_repr_attr;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Const;
use rustc_middle::ty::{Const, FeedConstTy};
use rustc_session::declare_lint_pass;
declare_clippy_lint! {
@ -53,14 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
}
}
fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
if let ItemKind::Struct(data, _) = &item.kind
// First check if last field is an array
&& let Some(last_field) = data.fields().last()
&& let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind
// Then check if that array is zero-sized
&& let length = Const::from_anon_const(cx.tcx, length.def_id)
&& let length = Const::from_const_arg(cx.tcx, length, FeedConstTy::No)
&& let length = length.try_eval_target_usize(cx.tcx, cx.param_env)
&& let Some(length) = length
{

View File

@ -5,10 +5,9 @@ use clippy_utils::{get_attr, higher};
use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::{
ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind,
QPath, StmtKind, TyKind,
self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind,
ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass;
@ -270,6 +269,22 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}
}
fn const_arg(&self, const_arg: &Binding<&ConstArg<'_>>) {
match const_arg.value.kind {
// FIXME: uncomment for ConstArgKind::Path
// ConstArgKind::Path(ref qpath) => {
// bind!(self, qpath);
// chain!(self, "let ConstArgKind::Path(ref {qpath}) = {const_arg}.kind");
// self.qpath(qpath);
// },
ConstArgKind::Anon(anon_const) => {
bind!(self, anon_const);
chain!(self, "let ConstArgKind::({anon_const}) = {const_arg}.kind");
self.body(field!(anon_const.body));
},
}
}
fn lit(&self, lit: &Binding<&Lit>) {
let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
macro_rules! kind {
@ -602,10 +617,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(value);
match length.value {
ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"),
ArrayLen::Body(anon_const) => {
bind!(self, anon_const);
chain!(self, "let ArrayLen::Body({anon_const}) = {length}");
self.body(field!(anon_const.body));
ArrayLen::Body(const_arg) => {
bind!(self, const_arg);
chain!(self, "let ArrayLen::Body({const_arg}) = {length}");
self.const_arg(const_arg);
},
}
},

View File

@ -227,7 +227,7 @@ impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_array_length(&mut self, left: ArrayLen<'_>, right: ArrayLen<'_>) -> bool {
match (left, right) {
(ArrayLen::Infer(..), ArrayLen::Infer(..)) => true,
(ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body),
(ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_const_arg(l_ct, r_ct),
(_, _) => false,
}
}
@ -1129,7 +1129,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_array_length(&mut self, length: ArrayLen<'_>) {
match length {
ArrayLen::Infer(..) => {},
ArrayLen::Body(anon_const) => self.hash_body(anon_const.body),
ArrayLen::Body(ct) => self.hash_const_arg(ct),
}
}

View File

@ -102,11 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::{
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
TyKind, UnOp,
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind,
ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem,
ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef,
TraitRef, TyKind, UnOp,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext};
@ -904,7 +904,9 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
},
ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
ExprKind::Repeat(x, ArrayLen::Body(len)) => {
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind
#[allow(irrefutable_let_patterns)] // FIXME
if let ConstArgKind::Anon(anon_const) = len.kind
&& let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
&& let LitKind::Int(v, _) = const_lit.node
&& v <= 32
&& is_default_equivalent(cx, x)
@ -933,7 +935,9 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
}) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
ExprKind::Repeat(_, ArrayLen::Body(len)) => {
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind
#[allow(irrefutable_let_patterns)] // FIXME
if let ConstArgKind::Anon(anon_const) = len.kind
&& let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
&& let LitKind::Int(v, _) = const_lit.node
{
return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);