Refactor is_range_literal
This commit is contained in:
parent
13962aff37
commit
5e709b2910
2 changed files with 18 additions and 23 deletions
|
@ -5401,29 +5401,29 @@ fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
|
||||||
body_ids
|
body_ids
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function checks if the specified expression is a built-in range literal.
|
/// Checks if the specified expression is a built-in range literal.
|
||||||
/// (See: `LoweringContext::lower_expr()`).
|
/// (See: `LoweringContext::lower_expr()`).
|
||||||
pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool {
|
pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool {
|
||||||
use hir::{Path, QPath, ExprKind, TyKind};
|
use hir::{Path, QPath, ExprKind, TyKind};
|
||||||
|
|
||||||
// We support `::std::ops::Range` and `::core::ops::Range` prefixes.
|
// Returns whether the given path represents a (desugared) range,
|
||||||
let is_range_path = |path: &Path| {
|
// either in std or core, i.e. has either a `::std::ops::Range` or
|
||||||
let mut segs = path.segments.iter().map(|seg| seg.ident.as_str());
|
// `::core::ops::Range` prefix.
|
||||||
|
fn is_range_path(path: &Path) -> bool {
|
||||||
|
let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.as_str().to_string()).collect();
|
||||||
|
let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
|
||||||
|
|
||||||
if let (Some(root), Some(std_core), Some(ops), Some(range), None) =
|
// "{{root}}" is the equivalent of `::` prefix in `Path`.
|
||||||
(segs.next(), segs.next(), segs.next(), segs.next(), segs.next())
|
if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
|
||||||
{
|
(*std_core == "std" || *std_core == "core") && range.starts_with("Range")
|
||||||
// "{{root}}" is the equivalent of `::` prefix in `Path`.
|
|
||||||
root == "{{root}}" && (std_core == "std" || std_core == "core")
|
|
||||||
&& ops == "ops" && range.starts_with("Range")
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let span_is_range_literal = |span: &Span| {
|
// Check whether a span corresponding to a range expression is a
|
||||||
// Check whether a span corresponding to a range expression
|
// range literal, rather than an explicit struct or `new()` call.
|
||||||
// is a range literal, rather than an explicit struct or `new()` call.
|
fn is_range_literal(sess: &Session, span: &Span) -> bool {
|
||||||
let source_map = sess.source_map();
|
let source_map = sess.source_map();
|
||||||
let end_point = source_map.end_point(*span);
|
let end_point = source_map.end_point(*span);
|
||||||
|
|
||||||
|
@ -5438,21 +5438,21 @@ pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool {
|
||||||
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
|
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
|
||||||
ExprKind::Struct(ref qpath, _, _) => {
|
ExprKind::Struct(ref qpath, _, _) => {
|
||||||
if let QPath::Resolved(None, ref path) = **qpath {
|
if let QPath::Resolved(None, ref path) = **qpath {
|
||||||
return is_range_path(&path) && span_is_range_literal(&expr.span);
|
return is_range_path(&path) && is_range_literal(sess, &expr.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `..` desugars to its struct path.
|
// `..` desugars to its struct path.
|
||||||
ExprKind::Path(QPath::Resolved(None, ref path)) => {
|
ExprKind::Path(QPath::Resolved(None, ref path)) => {
|
||||||
return is_range_path(&path) && span_is_range_literal(&expr.span);
|
return is_range_path(&path) && is_range_literal(sess, &expr.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
|
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
|
||||||
ExprKind::Call(ref func, _) => {
|
ExprKind::Call(ref func, _) => {
|
||||||
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
|
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
|
||||||
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
|
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
|
||||||
let call_to_new = segment.ident.as_str() == "new";
|
let new_call = segment.ident.as_str() == "new";
|
||||||
return is_range_path(&path) && span_is_range_literal(&expr.span) && call_to_new;
|
return is_range_path(&path) && is_range_literal(sess, &expr.span) && new_call;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,12 +92,7 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>(
|
||||||
LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(),
|
LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
let suggestion = format!(
|
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
|
||||||
"{}..={}{}",
|
|
||||||
start,
|
|
||||||
lit_val - 1,
|
|
||||||
suffix,
|
|
||||||
);
|
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
parent_expr.span,
|
parent_expr.span,
|
||||||
&"use an inclusive range instead",
|
&"use an inclusive range instead",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue