|
1 | 1 | #![allow(clippy::similar_names)] // `expr` and `expn`
|
2 | 2 |
|
3 |
| -use crate::visitors::{for_each_expr, Descend}; |
| 3 | +use crate::visitors::{for_each_expr, Descend, Visitable}; |
4 | 4 |
|
5 | 5 | use arrayvec::ArrayVec;
|
6 | 6 | use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
|
7 | 7 | use rustc_data_structures::fx::FxHashMap;
|
8 |
| -use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; |
| 8 | +use rustc_hir::{self as hir, Expr, ExprKind, HirId, LangItem, Node, QPath}; |
9 | 9 | use rustc_lint::LateContext;
|
10 | 10 | use rustc_span::def_id::DefId;
|
11 | 11 | use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
|
@@ -425,6 +425,39 @@ pub fn find_format_arg_expr<'hir, 'ast>(
|
425 | 425 | .ok_or(&target.expr)
|
426 | 426 | }
|
427 | 427 |
|
| 428 | +/// Given a start node, finds and extracts all format arguments from first occurance. |
| 429 | +/// |
| 430 | +/// ```ignore |
| 431 | +/// // vvvvv any format-like macro |
| 432 | +/// println!("Hello, {}!", "ferris") |
| 433 | +/// // ^^^^^^^^ returns these expressions |
| 434 | +/// ``` |
| 435 | +pub fn collect_format_args<'hir>(node: impl Visitable<'hir>) -> impl Iterator<Item = &'hir Expr<'hir>> { |
| 436 | + let args = for_each_expr(node, |expr| { |
| 437 | + if let ExprKind::Call( |
| 438 | + Expr { |
| 439 | + kind: |
| 440 | + ExprKind::Path(QPath::TypeRelative( |
| 441 | + rustc_hir::Ty { |
| 442 | + kind: rustc_hir::TyKind::Path(QPath::LangItem(LangItem::FormatArgument, ..)), |
| 443 | + .. |
| 444 | + }, |
| 445 | + .., |
| 446 | + )), |
| 447 | + .. |
| 448 | + }, |
| 449 | + args, |
| 450 | + ) = expr.kind |
| 451 | + { |
| 452 | + ControlFlow::Break(args) |
| 453 | + } else { |
| 454 | + ControlFlow::Continue(Descend::Yes) |
| 455 | + } |
| 456 | + }) |
| 457 | + .unwrap_or_default(); |
| 458 | + args.iter() |
| 459 | +} |
| 460 | + |
428 | 461 | /// Span of the `:` and format specifiers
|
429 | 462 | ///
|
430 | 463 | /// ```ignore
|
|
0 commit comments