Remove QPath::LangItem from ranges
This commit is contained in:
@@ -1484,7 +1484,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
||||
let e1 = self.lower_expr_mut(e1);
|
||||
let e2 = self.lower_expr_mut(e2);
|
||||
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
|
||||
let fn_path = self.make_lang_item_qpath(hir::LangItem::RangeInclusiveNew, span, None);
|
||||
let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));
|
||||
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
|
||||
}
|
||||
@@ -1570,7 +1570,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
|
||||
hir::ExprKind::Struct(
|
||||
self.arena.alloc(hir::QPath::LangItem(lang_item, span)),
|
||||
self.arena.alloc(self.make_lang_item_qpath(lang_item, span, None)),
|
||||
fields,
|
||||
hir::StructTailExpr::None,
|
||||
)
|
||||
|
||||
@@ -23,7 +23,9 @@ use rustc_index::IndexVec;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_span::{
|
||||
BytePos, DUMMY_SP, DesugaringKind, ErrorGuaranteed, Ident, Span, Symbol, kw, sym,
|
||||
};
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
use smallvec::SmallVec;
|
||||
use thin_vec::ThinVec;
|
||||
@@ -2600,102 +2602,21 @@ impl Expr<'_> {
|
||||
) => path1.res == path2.res,
|
||||
(
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeTo, _),
|
||||
[val1],
|
||||
&QPath::Resolved(None, &Path { res: Res::Def(_, path1_def_id), .. }),
|
||||
args1,
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeTo, _),
|
||||
[val2],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeToInclusive, _),
|
||||
[val1],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeToInclusive, _),
|
||||
[val2],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
|
||||
[val1],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
|
||||
[val2],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeFrom, _),
|
||||
[val1],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeFrom, _),
|
||||
[val2],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeFromCopy, _),
|
||||
[val1],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeFromCopy, _),
|
||||
[val2],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
) => val1.expr.equivalent_for_indexing(val2.expr),
|
||||
(
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::Range, _),
|
||||
[val1, val3],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::Range, _),
|
||||
[val2, val4],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeCopy, _),
|
||||
[val1, val3],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeCopy, _),
|
||||
[val2, val4],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeInclusiveCopy, _),
|
||||
[val1, val3],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeInclusiveCopy, _),
|
||||
[val2, val4],
|
||||
&QPath::Resolved(None, &Path { res: Res::Def(_, path2_def_id), .. }),
|
||||
args2,
|
||||
StructTailExpr::None,
|
||||
),
|
||||
) => {
|
||||
val1.expr.equivalent_for_indexing(val2.expr)
|
||||
&& val3.expr.equivalent_for_indexing(val4.expr)
|
||||
path2_def_id == path1_def_id
|
||||
&& is_range_literal(self)
|
||||
&& is_range_literal(other)
|
||||
&& std::iter::zip(args1, args2)
|
||||
.all(|(a, b)| a.expr.equivalent_for_indexing(b.expr))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
@@ -2713,30 +2634,29 @@ impl Expr<'_> {
|
||||
/// Checks if the specified expression is a built-in range literal.
|
||||
/// (See: `LoweringContext::lower_expr()`).
|
||||
pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
|
||||
ExprKind::Struct(ref qpath, _, _) => matches!(
|
||||
**qpath,
|
||||
QPath::LangItem(
|
||||
LangItem::Range
|
||||
| LangItem::RangeTo
|
||||
| LangItem::RangeFrom
|
||||
| LangItem::RangeFull
|
||||
| LangItem::RangeToInclusive
|
||||
| LangItem::RangeCopy
|
||||
| LangItem::RangeFromCopy
|
||||
| LangItem::RangeInclusiveCopy
|
||||
| LangItem::RangeToInclusiveCopy,
|
||||
..
|
||||
)
|
||||
),
|
||||
|
||||
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
|
||||
ExprKind::Call(ref func, _) => {
|
||||
matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)))
|
||||
}
|
||||
|
||||
_ => false,
|
||||
if let ExprKind::Struct(QPath::Resolved(None, path), _, StructTailExpr::None) = expr.kind
|
||||
&& let [.., segment] = path.segments
|
||||
&& let sym::RangeFrom
|
||||
| sym::RangeFull
|
||||
| sym::Range
|
||||
| sym::RangeToInclusive
|
||||
| sym::RangeTo
|
||||
| sym::RangeFromCopy
|
||||
| sym::RangeCopy
|
||||
| sym::RangeInclusiveCopy
|
||||
| sym::RangeToInclusiveCopy = segment.ident.name
|
||||
&& expr.span.is_desugaring(DesugaringKind::RangeExpr)
|
||||
{
|
||||
true
|
||||
} else if let ExprKind::Call(func, _) = &expr.kind
|
||||
&& let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
|
||||
&& let [.., segment] = path.segments
|
||||
&& let sym::range_inclusive_new = segment.ident.name
|
||||
&& expr.span.is_desugaring(DesugaringKind::RangeExpr)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath, find_attr};
|
||||
use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
|
||||
use rustc_hir_analysis::NoVariantNamed;
|
||||
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
|
||||
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
|
||||
@@ -2506,9 +2506,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
args: GenericArgsRef<'tcx>,
|
||||
mut err: Diag<'_>,
|
||||
) {
|
||||
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
|
||||
if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [range_start, range_end], _) =
|
||||
last_expr_field.expr.kind
|
||||
if is_range_literal(last_expr_field.expr)
|
||||
&& let ExprKind::Struct(&qpath, [range_start, range_end], _) = last_expr_field.expr.kind
|
||||
&& self.tcx.qpath_is_lang_item(qpath, LangItem::Range)
|
||||
&& let variant_field =
|
||||
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
|
||||
&& let range_def_id = self.tcx.lang_items().range_struct()
|
||||
|
||||
@@ -1032,8 +1032,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// inherent impl, we need to record the
|
||||
// `T` for posterity (see `UserSelfTy` for
|
||||
// details).
|
||||
let self_ty = self_ty.expect("UFCS sugared assoc missing Self").raw;
|
||||
user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty });
|
||||
// Generated desugaring code may have a path without a self.
|
||||
user_self_ty = self_ty.map(|self_ty| UserSelfTy {
|
||||
impl_def_id: container_id,
|
||||
self_ty: self_ty.raw,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, lis
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath};
|
||||
use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal};
|
||||
use rustc_hir_analysis::check::potentially_plural_count;
|
||||
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
|
||||
use rustc_index::IndexVec;
|
||||
@@ -2052,8 +2052,9 @@ impl<'a, 'b, 'tcx> FnCallDiagCtxt<'a, 'b, 'tcx> {
|
||||
fn detect_dotdot(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'tcx>) {
|
||||
if let ty::Adt(adt, _) = ty.kind()
|
||||
&& self.tcx().is_lang_item(adt.did(), hir::LangItem::RangeFull)
|
||||
&& let hir::ExprKind::Struct(hir::QPath::LangItem(hir::LangItem::RangeFull, _), [], _) =
|
||||
expr.kind
|
||||
&& is_range_literal(expr)
|
||||
&& let hir::ExprKind::Struct(&path, [], _) = expr.kind
|
||||
&& self.tcx().qpath_is_lang_item(path, hir::LangItem::RangeFull)
|
||||
{
|
||||
// We have `Foo(a, .., c)`, where the user might be trying to use the "rest" syntax
|
||||
// from default field values, which is not supported on tuples.
|
||||
|
||||
@@ -11,7 +11,7 @@ use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
|
||||
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
|
||||
WherePredicateKind, expr_needs_parens,
|
||||
WherePredicateKind, expr_needs_parens, is_range_literal,
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_hir_analysis::suggest_impl_trait;
|
||||
@@ -1664,7 +1664,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return false;
|
||||
}
|
||||
match expr.kind {
|
||||
ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => {
|
||||
ExprKind::Struct(&qpath, [start, end], _)
|
||||
if is_range_literal(expr)
|
||||
&& self.tcx.qpath_is_lang_item(qpath, LangItem::Range) =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()),
|
||||
"remove the unnecessary `.` operator for a floating point literal",
|
||||
@@ -1673,24 +1676,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
true
|
||||
}
|
||||
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => {
|
||||
ExprKind::Struct(&qpath, [arg], _)
|
||||
if is_range_literal(expr)
|
||||
&& let Some(qpath @ (LangItem::RangeFrom | LangItem::RangeTo)) =
|
||||
self.tcx.qpath_lang_item(qpath) =>
|
||||
{
|
||||
let range_span = expr.span.parent_callsite().unwrap();
|
||||
err.span_suggestion_verbose(
|
||||
range_span.with_lo(start.expr.span.hi()),
|
||||
"remove the unnecessary `.` operator for a floating point literal",
|
||||
'.',
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
true
|
||||
}
|
||||
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => {
|
||||
let range_span = expr.span.parent_callsite().unwrap();
|
||||
err.span_suggestion_verbose(
|
||||
range_span.until(end.expr.span),
|
||||
"remove the unnecessary `.` operator and add an integer part for a floating point literal",
|
||||
"0.",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
match qpath {
|
||||
LangItem::RangeFrom => {
|
||||
err.span_suggestion_verbose(
|
||||
range_span.with_lo(arg.expr.span.hi()),
|
||||
"remove the unnecessary `.` operator for a floating point literal",
|
||||
'.',
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_suggestion_verbose(
|
||||
range_span.until(arg.expr.span),
|
||||
"remove the unnecessary `.` operator and add an integer part for a floating point literal",
|
||||
"0.",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
ExprKind::Lit(Spanned {
|
||||
@@ -3497,11 +3506,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if !hir::is_range_literal(expr) {
|
||||
return;
|
||||
}
|
||||
let hir::ExprKind::Struct(hir::QPath::LangItem(LangItem::Range, ..), [start, end], _) =
|
||||
expr.kind
|
||||
else {
|
||||
let hir::ExprKind::Struct(&qpath, [start, end], _) = expr.kind else {
|
||||
return;
|
||||
};
|
||||
if !self.tcx.qpath_is_lang_item(qpath, LangItem::Range) {
|
||||
return;
|
||||
}
|
||||
if let hir::Node::ExprField(_) = self.tcx.parent_hir_node(expr.hir_id) {
|
||||
// Ignore `Foo { field: a..Default::default() }`
|
||||
return;
|
||||
|
||||
@@ -19,7 +19,9 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath, find_attr};
|
||||
use rustc_hir::{
|
||||
self as hir, ExprKind, HirId, Node, PathSegment, QPath, find_attr, is_range_literal,
|
||||
};
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
|
||||
@@ -2412,22 +2414,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if let SelfSource::MethodCall(expr) = source {
|
||||
for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) {
|
||||
if let Node::Expr(parent_expr) = parent {
|
||||
if !is_range_literal(parent_expr) {
|
||||
continue;
|
||||
}
|
||||
let lang_item = match parent_expr.kind {
|
||||
ExprKind::Struct(qpath, _, _) => match *qpath {
|
||||
QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
|
||||
QPath::LangItem(LangItem::RangeCopy, ..) => Some(LangItem::RangeCopy),
|
||||
QPath::LangItem(LangItem::RangeInclusiveCopy, ..) => {
|
||||
Some(LangItem::RangeInclusiveCopy)
|
||||
}
|
||||
QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
|
||||
QPath::LangItem(LangItem::RangeToInclusive, ..) => {
|
||||
Some(LangItem::RangeToInclusive)
|
||||
}
|
||||
ExprKind::Struct(qpath, _, _) => match tcx.qpath_lang_item(*qpath) {
|
||||
Some(
|
||||
lang_item @ (LangItem::Range
|
||||
| LangItem::RangeCopy
|
||||
| LangItem::RangeInclusiveCopy
|
||||
| LangItem::RangeTo
|
||||
| LangItem::RangeToInclusive),
|
||||
) => Some(lang_item),
|
||||
_ => None,
|
||||
},
|
||||
ExprKind::Call(func, _) => match func.kind {
|
||||
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
|
||||
ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
|
||||
ExprKind::Path(qpath)
|
||||
if tcx.qpath_is_lang_item(qpath, LangItem::RangeInclusiveNew) =>
|
||||
{
|
||||
Some(LangItem::RangeInclusiveStruct)
|
||||
}
|
||||
_ => None,
|
||||
|
||||
@@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||
let note = "the suggestion might not be applicable in constant blocks";
|
||||
let ty = cx.typeck_results().expr_ty(array).peel_refs();
|
||||
let allowed_in_tests = self.allow_indexing_slicing_in_tests && is_in_test(cx.tcx, expr.hir_id);
|
||||
if let Some(range) = higher::Range::hir(index) {
|
||||
if let Some(range) = higher::Range::hir(cx, index) {
|
||||
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
|
||||
if let ty::Array(_, s) = ty.kind() {
|
||||
let size: u128 = if let Some(size) = s.try_to_target_usize(cx.tcx) {
|
||||
|
||||
@@ -178,7 +178,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||
Finite
|
||||
}
|
||||
},
|
||||
ExprKind::Struct(..) => higher::Range::hir(expr).is_some_and(|r| r.end.is_none()).into(),
|
||||
ExprKind::Struct(..) => higher::Range::hir(cx, expr).is_some_and(|r| r.end.is_none()).into(),
|
||||
_ => Finite,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ fn check_index_usage<'tcx>(
|
||||
fn index_consumed_at<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||
for (_, node) in cx.tcx.hir_parent_iter(expr.hir_id) {
|
||||
match node {
|
||||
Node::Expr(expr) if higher::Range::hir(expr).is_some() => {},
|
||||
Node::Expr(expr) if higher::Range::hir(cx, expr).is_some() => {},
|
||||
Node::ExprField(_) => {},
|
||||
Node::Expr(expr) => return Some(expr),
|
||||
_ => break,
|
||||
|
||||
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
|
||||
end: Some(end),
|
||||
limits,
|
||||
span: _,
|
||||
}) = higher::Range::hir(arg)
|
||||
}) = higher::Range::hir(cx, arg)
|
||||
// the var must be a single name
|
||||
&& let PatKind::Binding(_, canonical_id, _, _) = pat.kind
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
|
||||
end: Some(end),
|
||||
limits: RangeLimits::HalfOpen,
|
||||
span: _,
|
||||
}) = higher::Range::hir(arg)
|
||||
}) = higher::Range::hir(cx, arg)
|
||||
&& let ExprKind::Lit(Spanned {
|
||||
node: LitKind::Int(Pu128(0), _),
|
||||
..
|
||||
|
||||
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
..
|
||||
}) = higher::Range::hir(arg)
|
||||
}) = higher::Range::hir(cx, arg)
|
||||
&& let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end))
|
||||
&& (mut_id_start.is_some() || mut_id_end.is_some())
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(
|
||||
ref end,
|
||||
limits,
|
||||
span,
|
||||
}) = higher::Range::hir(arg)
|
||||
}) = higher::Range::hir(cx, arg)
|
||||
// the var must be a single name
|
||||
&& let PatKind::Binding(_, canonical_id, ident, _) = pat.kind
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ pub(super) fn check<'tcx>(
|
||||
arg_snip = format!("({arg_snip})").into();
|
||||
}
|
||||
|
||||
if clippy_utils::higher::Range::hir(arg_expression).is_some() {
|
||||
if clippy_utils::higher::Range::hir(cx, arg_expression).is_some() {
|
||||
let range_expr = snippet(cx, arg_expression.span, "?").to_string();
|
||||
|
||||
let sugg = snippet(cx, arg_expression.span, "..");
|
||||
|
||||
@@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
||||
end: Some(end),
|
||||
limits: RangeLimits::Closed,
|
||||
span: _,
|
||||
}) = higher::Range::hir(receiver)
|
||||
}) = higher::Range::hir(cx, receiver)
|
||||
&& !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
|
||||
{
|
||||
let arg = peel_ref_operators(cx, arg);
|
||||
|
||||
@@ -207,7 +207,7 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
ExprKind::Index(arr, range, _) => match arr.kind {
|
||||
ExprKind::Array([]) => is_range_literal(range),
|
||||
ExprKind::Array(_) => {
|
||||
let Some(range) = clippy_utils::higher::Range::hir(range) else {
|
||||
let Some(range) = clippy_utils::higher::Range::hir(cx, range) else {
|
||||
return false;
|
||||
};
|
||||
range.end.is_some_and(|e| clippy_utils::is_integer_const(cx, e, 0))
|
||||
|
||||
@@ -237,7 +237,7 @@ fn find_stripping<'tcx>(
|
||||
if is_ref_str(self.cx, ex)
|
||||
&& let unref = peel_ref(ex)
|
||||
&& let ExprKind::Index(indexed, index, _) = &unref.kind
|
||||
&& let Some(higher::Range { start, end, .. }) = higher::Range::hir(index)
|
||||
&& let Some(higher::Range { start, end, .. }) = higher::Range::hir(self.cx, index)
|
||||
&& let ExprKind::Path(path) = &indexed.kind
|
||||
&& self.cx.qpath_res(path, ex.hir_id) == self.target
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
|
||||
end: None,
|
||||
limits: ast::RangeLimits::HalfOpen,
|
||||
span: _,
|
||||
}) = higher::Range::hir(index_expr)
|
||||
}) = higher::Range::hir(cx, index_expr)
|
||||
&& let hir::ExprKind::Lit(start_lit) = &start_expr.kind
|
||||
&& let ast::LitKind::Int(start_idx, _) = start_lit.node
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ pub(super) fn check(
|
||||
method_name_span: Span,
|
||||
) {
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
if let Some(range) = higher::Range::hir(receiver)
|
||||
if let Some(range) = higher::Range::hir(cx, receiver)
|
||||
&& let ExprKind::Closure(Closure { body, .. }) = arg.kind
|
||||
&& let body_hir = cx.tcx.hir_body(*body)
|
||||
&& let Body {
|
||||
|
||||
@@ -11,7 +11,7 @@ use super::RANGE_ZIP_WITH_LEN;
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) {
|
||||
if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
|
||||
// range expression in `.zip()` call: `0..x.len()`
|
||||
&& let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg)
|
||||
&& let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(cx, zip_arg)
|
||||
&& is_integer_const(cx, start, 0)
|
||||
// `.len()` call
|
||||
&& let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind
|
||||
|
||||
@@ -220,14 +220,14 @@ impl<'hir> IndexEntry<'hir> {
|
||||
///
|
||||
/// E.g. for `5` this returns `Some(5)`, for `..5` this returns `Some(4)`,
|
||||
/// for `..=5` this returns `Some(5)`
|
||||
fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> {
|
||||
fn upper_index_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<usize> {
|
||||
if let ExprKind::Lit(lit) = &expr.kind
|
||||
&& let LitKind::Int(Pu128(index), _) = lit.node
|
||||
{
|
||||
Some(index as usize)
|
||||
} else if let Some(higher::Range {
|
||||
end: Some(end), limits, ..
|
||||
}) = higher::Range::hir(expr)
|
||||
}) = higher::Range::hir(cx, expr)
|
||||
&& let ExprKind::Lit(lit) = &end.kind
|
||||
&& let LitKind::Int(Pu128(index @ 1..), _) = lit.node
|
||||
{
|
||||
@@ -244,7 +244,7 @@ fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> {
|
||||
fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnindexMap<u64, Vec<IndexEntry<'hir>>>) {
|
||||
if let ExprKind::Index(slice, index_lit, _) = expr.kind
|
||||
&& cx.typeck_results().expr_ty_adjusted(slice).peel_refs().is_slice()
|
||||
&& let Some(index) = upper_index_expr(index_lit)
|
||||
&& let Some(index) = upper_index_expr(cx, index_lit)
|
||||
{
|
||||
let hash = hash_expr(cx, slice);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NeedlessParensOnRangeLiterals {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let Some(higher::Range { start, end, .. }) = higher::Range::hir(expr) {
|
||||
if let Some(higher::Range { start, end, .. }) = higher::Range::hir(cx, expr) {
|
||||
if let Some(start) = start {
|
||||
check_for_parens(cx, start, true);
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ fn check_range_switch<'tcx>(
|
||||
msg: &'static str,
|
||||
operator: &str,
|
||||
) {
|
||||
if let Some(range) = higher::Range::hir(expr)
|
||||
if let Some(range) = higher::Range::hir(cx, expr)
|
||||
&& let higher::Range {
|
||||
start,
|
||||
end: Some(end),
|
||||
@@ -571,7 +571,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
end: Some(end),
|
||||
limits,
|
||||
span,
|
||||
}) = higher::Range::hir(expr)
|
||||
}) = higher::Range::hir(cx, expr)
|
||||
&& let ty = cx.typeck_results().expr_ty(start)
|
||||
&& let ty::Int(_) | ty::Uint(_) = ty.kind()
|
||||
&& let ecx = ConstEvalCtxt::new(cx)
|
||||
|
||||
@@ -6,7 +6,7 @@ use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_no_std_crate, sym};
|
||||
use rustc_ast::{LitIntType, LitKind, UintTy};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr};
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, StructTailExpr};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
@@ -86,12 +86,12 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
|
||||
return;
|
||||
};
|
||||
|
||||
let ExprKind::Struct(QPath::LangItem(lang_item, ..), [start, end], StructTailExpr::None) = inner_expr.kind
|
||||
let ExprKind::Struct(&qpath, [start, end], StructTailExpr::None) = inner_expr.kind
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if matches!(lang_item, LangItem::Range)
|
||||
if cx.tcx.qpath_is_lang_item(qpath, LangItem::Range)
|
||||
&& let ty = cx.typeck_results().expr_ty(start.expr)
|
||||
&& let Some(snippet) = span.get_source_text(cx)
|
||||
// `is_from_proc_macro` will skip any `vec![]`. Let's not!
|
||||
|
||||
@@ -6,7 +6,7 @@ use clippy_utils::{
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::declare_lint_pass;
|
||||
@@ -266,7 +266,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
||||
&& expressions[0].1.is_empty()
|
||||
|
||||
// Check for slicer
|
||||
&& let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind
|
||||
&& let ExprKind::Struct(&qpath, _, _) = right.kind
|
||||
&& cx.tcx.qpath_is_lang_item(qpath, LangItem::Range)
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let string_expression = &expressions[0].0;
|
||||
|
||||
@@ -215,14 +215,12 @@ pub struct Range<'a> {
|
||||
impl<'a> Range<'a> {
|
||||
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
|
||||
#[expect(clippy::similar_names)]
|
||||
pub fn hir(expr: &'a Expr<'_>) -> Option<Range<'a>> {
|
||||
pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<Range<'a>> {
|
||||
let span = expr.range_span()?;
|
||||
match expr.kind {
|
||||
ExprKind::Call(path, [arg1, arg2])
|
||||
if matches!(
|
||||
path.kind,
|
||||
ExprKind::Path(QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..))
|
||||
) =>
|
||||
if let ExprKind::Path(qpath) = path.kind
|
||||
&& cx.tcx.qpath_is_lang_item(qpath, hir::LangItem::RangeInclusiveNew) =>
|
||||
{
|
||||
Some(Range {
|
||||
start: Some(arg1),
|
||||
@@ -231,14 +229,14 @@ impl<'a> Range<'a> {
|
||||
span,
|
||||
})
|
||||
},
|
||||
ExprKind::Struct(path, fields, StructTailExpr::None) => match (path, fields) {
|
||||
(QPath::LangItem(hir::LangItem::RangeFull, ..), []) => Some(Range {
|
||||
ExprKind::Struct(&qpath, fields, StructTailExpr::None) => match (cx.tcx.qpath_lang_item(qpath)?, fields) {
|
||||
(hir::LangItem::RangeFull, []) => Some(Range {
|
||||
start: None,
|
||||
end: None,
|
||||
limits: ast::RangeLimits::HalfOpen,
|
||||
span,
|
||||
}),
|
||||
(QPath::LangItem(hir::LangItem::RangeFrom, ..), [field]) if field.ident.name == sym::start => {
|
||||
(hir::LangItem::RangeFrom, [field]) if field.ident.name == sym::start => {
|
||||
Some(Range {
|
||||
start: Some(field.expr),
|
||||
end: None,
|
||||
@@ -246,7 +244,7 @@ impl<'a> Range<'a> {
|
||||
span,
|
||||
})
|
||||
},
|
||||
(QPath::LangItem(hir::LangItem::Range, ..), [field1, field2]) => {
|
||||
(hir::LangItem::Range, [field1, field2]) => {
|
||||
let (start, end) = match (field1.ident.name, field2.ident.name) {
|
||||
(sym::start, sym::end) => (field1.expr, field2.expr),
|
||||
(sym::end, sym::start) => (field2.expr, field1.expr),
|
||||
@@ -259,7 +257,7 @@ impl<'a> Range<'a> {
|
||||
span,
|
||||
})
|
||||
},
|
||||
(QPath::LangItem(hir::LangItem::RangeToInclusive, ..), [field]) if field.ident.name == sym::end => {
|
||||
(hir::LangItem::RangeToInclusive, [field]) if field.ident.name == sym::end => {
|
||||
Some(Range {
|
||||
start: None,
|
||||
end: Some(field.expr),
|
||||
@@ -267,7 +265,7 @@ impl<'a> Range<'a> {
|
||||
span,
|
||||
})
|
||||
},
|
||||
(QPath::LangItem(hir::LangItem::RangeTo, ..), [field]) if field.ident.name == sym::end => Some(Range {
|
||||
(hir::LangItem::RangeTo, [field]) if field.ident.name == sym::end => Some(Range {
|
||||
start: None,
|
||||
end: Some(field.expr),
|
||||
limits: ast::RangeLimits::HalfOpen,
|
||||
|
||||
@@ -1282,7 +1282,7 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
|
||||
/// If the given `Expr` is not some kind of range, the function returns `false`.
|
||||
pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if let Some(Range { start, end, limits, .. }) = Range::hir(expr) {
|
||||
if let Some(Range { start, end, limits, .. }) = Range::hir(cx, expr) {
|
||||
let start_is_none_or_min = start.is_none_or(|start| {
|
||||
if let rustc_ty::Adt(_, subst) = ty.kind()
|
||||
&& let bnd_ty = subst.type_at(0)
|
||||
|
||||
@@ -59,7 +59,7 @@ impl<'a> Sugg<'a> {
|
||||
pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
|
||||
let ctxt = expr.span.ctxt();
|
||||
let get_snippet = |span| snippet_with_context(cx, span, ctxt, "", &mut Applicability::Unspecified).0;
|
||||
snippet_opt(cx, expr.span).map(|_| Self::hir_from_snippet(expr, get_snippet))
|
||||
snippet_opt(cx, expr.span).map(|_| Self::hir_from_snippet(cx, expr, get_snippet))
|
||||
}
|
||||
|
||||
/// Convenience function around `hir_opt` for suggestions with a default
|
||||
@@ -115,7 +115,7 @@ impl<'a> Sugg<'a> {
|
||||
Box::new(Self::hir_with_context(cx, inner, ctxt, default, applicability)),
|
||||
)
|
||||
} else {
|
||||
Self::hir_from_snippet(expr, |span| {
|
||||
Self::hir_from_snippet(cx, expr, |span| {
|
||||
snippet_with_context(cx, span, ctxt, default, applicability).0
|
||||
})
|
||||
}
|
||||
@@ -127,8 +127,8 @@ impl<'a> Sugg<'a> {
|
||||
|
||||
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
|
||||
/// function variants of `Sugg`, since these use different snippet functions.
|
||||
fn hir_from_snippet(expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>) -> Self {
|
||||
if let Some(range) = higher::Range::hir(expr) {
|
||||
fn hir_from_snippet(cx: &LateContext<'_>, expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>) -> Self {
|
||||
if let Some(range) = higher::Range::hir(cx, expr) {
|
||||
let op = AssocOp::Range(range.limits);
|
||||
let start = range.start.map_or("".into(), |expr| get_snippet(expr.span));
|
||||
let end = range.end.map_or("".into(), |expr| get_snippet(expr.span));
|
||||
@@ -166,7 +166,7 @@ impl<'a> Sugg<'a> {
|
||||
| ExprKind::Use(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)),
|
||||
ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
|
||||
ExprKind::DropTemps(inner) => Self::hir_from_snippet(cx, inner, get_snippet),
|
||||
ExprKind::Assign(lhs, rhs, _) => {
|
||||
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
|
||||
},
|
||||
|
||||
@@ -2,7 +2,8 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, name, None) = pat.kind
|
||||
&& name.as_str() == "y"
|
||||
&& let ExprKind::Struct(qpath, fields, None) = arg.kind
|
||||
&& matches!(qpath, QPath::LangItem(LangItem::Range, _))
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
|
||||
&& paths::CORE_OPS_RANGE_RANGE.matches(cx, def_id) // Add the path to `clippy_utils::paths` if needed
|
||||
&& fields.len() == 2
|
||||
&& fields[0].ident.as_str() == "start"
|
||||
&& let ExprKind::Lit(ref lit) = fields[0].expr.kind
|
||||
@@ -23,7 +24,8 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
|
||||
if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
|
||||
&& let PatKind::Wild = pat.kind
|
||||
&& let ExprKind::Struct(qpath, fields, None) = arg.kind
|
||||
&& matches!(qpath, QPath::LangItem(LangItem::Range, _))
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
|
||||
&& paths::CORE_OPS_RANGE_RANGE.matches(cx, def_id) // Add the path to `clippy_utils::paths` if needed
|
||||
&& fields.len() == 2
|
||||
&& fields[0].ident.as_str() == "start"
|
||||
&& let ExprKind::Lit(ref lit) = fields[0].expr.kind
|
||||
@@ -43,7 +45,8 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
|
||||
if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
|
||||
&& let PatKind::Wild = pat.kind
|
||||
&& let ExprKind::Struct(qpath, fields, None) = arg.kind
|
||||
&& matches!(qpath, QPath::LangItem(LangItem::Range, _))
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
|
||||
&& paths::CORE_OPS_RANGE_RANGE.matches(cx, def_id) // Add the path to `clippy_utils::paths` if needed
|
||||
&& fields.len() == 2
|
||||
&& fields[0].ident.as_str() == "start"
|
||||
&& let ExprKind::Lit(ref lit) = fields[0].expr.kind
|
||||
|
||||
@@ -2,7 +2,8 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, name, None) = pat.kind
|
||||
&& name.as_str() == "i"
|
||||
&& let ExprKind::Struct(qpath, fields, None) = arg.kind
|
||||
&& matches!(qpath, QPath::LangItem(LangItem::Range, _))
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
|
||||
&& paths::CORE_OPS_RANGE_RANGE.matches(cx, def_id) // Add the path to `clippy_utils::paths` if needed
|
||||
&& fields.len() == 2
|
||||
&& fields[0].ident.as_str() == "start"
|
||||
&& let ExprKind::Lit(ref lit) = fields[0].expr.kind
|
||||
|
||||
@@ -29,11 +29,9 @@ impl Foo<'_> {
|
||||
fn d<'a>(&self, x: &'a u32) { }
|
||||
|
||||
// FIXME: impl Traits printed as just `/*impl Trait*/`, ugh
|
||||
fn iter1<'a>(&self)
|
||||
-> /*impl Trait*/ { #[lang = "Range"] { start: 0, end: 1 } }
|
||||
fn iter1<'a>(&self) -> /*impl Trait*/ { Range { start: 0, end: 1 } }
|
||||
|
||||
fn iter2(&self)
|
||||
-> /*impl Trait*/ { #[lang = "Range"] { start: 0, end: 1 } }
|
||||
fn iter2(&self) -> /*impl Trait*/ { Range { start: 0, end: 1 } }
|
||||
}
|
||||
|
||||
fn a(x: Foo<'_>) { }
|
||||
|
||||
@@ -273,14 +273,14 @@ mod expressions {
|
||||
/// ExprKind::Range
|
||||
fn expr_range() {
|
||||
let (lo, hi);
|
||||
#[lang = "RangeFull"] { };
|
||||
#[lang = "RangeTo"] { end: hi };
|
||||
#[lang = "RangeFrom"] { start: lo };
|
||||
#[lang = "Range"] { start: lo, end: hi };
|
||||
#[lang = "Range"] { start: lo, end: hi };
|
||||
#[lang = "RangeToInclusive"] { end: hi };
|
||||
#[lang = "range_inclusive_new"](lo, hi);
|
||||
#[lang = "range_inclusive_new"](-2, -1);
|
||||
RangeFull { };
|
||||
RangeTo { end: hi };
|
||||
RangeFrom { start: lo };
|
||||
Range { start: lo, end: hi };
|
||||
Range { start: lo, end: hi };
|
||||
RangeToInclusive { end: hi };
|
||||
range_inclusive_new(lo, hi);
|
||||
range_inclusive_new(-2, -1);
|
||||
}
|
||||
|
||||
/// ExprKind::Underscore
|
||||
|
||||
Reference in New Issue
Block a user