summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_utils/src/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_utils/src/macros.rs')
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs76
1 files changed, 45 insertions, 31 deletions
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 77c5f1155..be6133d32 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -1,6 +1,5 @@
#![allow(clippy::similar_names)] // `expr` and `expn`
-use crate::is_path_diagnostic_item;
use crate::source::snippet_opt;
use crate::visitors::{for_each_expr, Descend};
@@ -8,7 +7,7 @@ use arrayvec::ArrayVec;
use itertools::{izip, Either, Itertools};
use rustc_ast::ast::LitKind;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
+use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind};
use rustc_lexer::unescape::unescape_literal;
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
use rustc_lint::LateContext;
@@ -328,7 +327,7 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
} else {
match cx.tcx.item_name(macro_call.def_id) {
// `cfg!(debug_assertions)` in `debug_assert!`
- sym::cfg => ControlFlow::CONTINUE,
+ sym::cfg => ControlFlow::Continue(()),
// assert!(other_macro!(..))
_ => ControlFlow::Break(true),
}
@@ -392,11 +391,18 @@ impl FormatString {
};
let mut unescaped = String::with_capacity(inner.len());
+ // Sometimes the original string comes from a macro which accepts a malformed string, such as in a
+ // #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the
+ // string from the span will not be possible, so we will just return None here.
+ let mut unparsable = false;
unescape_literal(inner, mode, &mut |_, ch| match ch {
Ok(ch) => unescaped.push(ch),
Err(e) if !e.is_fatal() => (),
- Err(e) => panic!("{e:?}"),
+ Err(_) => unparsable = true,
});
+ if unparsable {
+ return None;
+ }
let mut parts = Vec::new();
let _: Option<!> = for_each_expr(pieces, |expr| {
@@ -439,8 +445,7 @@ impl<'tcx> FormatArgsValues<'tcx> {
// ArgumentV1::from_usize(<val>)
if let ExprKind::Call(callee, [val]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
- && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
- && path.segments.last().unwrap().ident.name == sym::ArgumentV1
+ && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind
{
let val_idx = if val.span.ctxt() == expr.span.ctxt()
&& let ExprKind::Field(_, field) = val.kind
@@ -486,20 +491,6 @@ struct ParamPosition {
impl<'tcx> Visitor<'tcx> for ParamPosition {
fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
- fn parse_count(expr: &Expr<'_>) -> Option<usize> {
- // ::core::fmt::rt::v1::Count::Param(1usize),
- if let ExprKind::Call(ctor, [val]) = expr.kind
- && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
- && path.segments.last()?.ident.name == sym::Param
- && let ExprKind::Lit(lit) = &val.kind
- && let LitKind::Int(pos, _) = lit.node
- {
- Some(pos as usize)
- } else {
- None
- }
- }
-
match field.ident.name {
sym::position => {
if let ExprKind::Lit(lit) = &field.expr.kind
@@ -519,15 +510,41 @@ impl<'tcx> Visitor<'tcx> for ParamPosition {
}
}
+fn parse_count(expr: &Expr<'_>) -> Option<usize> {
+ // <::core::fmt::rt::v1::Count>::Param(1usize),
+ if let ExprKind::Call(ctor, [val]) = expr.kind
+ && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind
+ && path.ident.name == sym::Param
+ && let ExprKind::Lit(lit) = &val.kind
+ && let LitKind::Int(pos, _) = lit.node
+ {
+ Some(pos as usize)
+ } else {
+ None
+ }
+}
+
/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
if let ExprKind::AddrOf(.., array) = fmt_arg.kind
&& let ExprKind::Array(specs) = array.kind
{
Some(specs.iter().map(|spec| {
- let mut position = ParamPosition::default();
- position.visit_expr(spec);
- position
+ if let ExprKind::Call(f, args) = spec.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind
+ && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind
+ && f.ident.name == sym::new
+ && let [position, _fill, _align, _flags, precision, width] = args
+ && let ExprKind::Lit(position) = &position.kind
+ && let LitKind::Int(position, _) = position.node {
+ ParamPosition {
+ value: position as usize,
+ width: parse_count(width),
+ precision: parse_count(precision),
+ }
+ } else {
+ ParamPosition::default()
+ }
}))
} else {
None
@@ -701,8 +718,8 @@ pub struct FormatSpec<'tcx> {
pub fill: Option<char>,
/// Optionally specified alignment.
pub align: Alignment,
- /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
- pub flags: u32,
+ /// Whether all flag options are set to default (no flags specified).
+ pub no_flags: bool,
/// Represents either the maximum width or the integer precision.
pub precision: Count<'tcx>,
/// The minimum width, will be padded according to `width`/`align`
@@ -718,7 +735,7 @@ impl<'tcx> FormatSpec<'tcx> {
Some(Self {
fill: spec.fill,
align: spec.align,
- flags: spec.flags,
+ no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(),
precision: Count::new(
FormatParamUsage::Precision,
spec.precision,
@@ -760,10 +777,7 @@ impl<'tcx> FormatSpec<'tcx> {
/// Has no other formatting specifiers than setting the format trait. returns true for `{}`,
/// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}`
pub fn is_default_for_trait(&self) -> bool {
- self.width.is_implied()
- && self.precision.is_implied()
- && self.align == Alignment::AlignUnknown
- && self.flags == 0
+ self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown && self.no_flags
}
}
@@ -890,7 +904,7 @@ impl<'tcx> FormatArgsExpn<'tcx> {
// ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
- && is_path_diagnostic_item(cx, ty, sym::Arguments)
+ && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind
&& matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
{
let format_string = FormatString::new(cx, pieces)?;