|
2 | 2 |
|
3 | 3 | #![deny(clippy::missing_docs_in_private_items)]
|
4 | 4 |
|
5 |
| -use crate::{is_expn_of, match_def_path, paths}; |
| 5 | +use crate::{is_expn_of, match_def_path, paths, source::snippet_with_applicability}; |
6 | 6 | use if_chain::if_chain;
|
7 | 7 | use rustc_ast::ast::{self, LitKind};
|
| 8 | +use rustc_errors::Applicability; |
8 | 9 | use rustc_hir as hir;
|
9 | 10 | use rustc_hir::{Arm, Block, BorrowKind, Expr, ExprKind, LoopSource, MatchSource, Node, Pat, StmtKind, UnOp};
|
10 | 11 | use rustc_lint::LateContext;
|
11 | 12 | use rustc_span::{sym, ExpnKind, Span, Symbol};
|
12 | 13 |
|
| 14 | +use std::borrow::Cow; |
| 15 | + |
13 | 16 | /// The essential nodes of a desugared for loop as well as the entire span:
|
14 | 17 | /// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`.
|
15 | 18 | pub struct ForLoop<'tcx> {
|
@@ -446,14 +449,33 @@ impl<'tcx> AssertExpn<'tcx> {
|
446 | 449 | if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
|
447 | 450 | // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
|
448 | 451 | if_chain! {
|
449 |
| - if let Some(If { cond, .. }) = If::hir(matchexpr); |
| 452 | + if let Some(If { cond, then, .. }) = If::hir(matchexpr); |
450 | 453 | if let ExprKind::Unary(UnOp::Not, condition) = cond.kind;
|
451 | 454 | then {
|
452 |
| - return Some(Self { |
453 |
| - first_assert_argument: condition, |
454 |
| - second_assert_argument: None, |
455 |
| - format_arg: None, // FIXME actually parse the aguments |
456 |
| - }); |
| 455 | + if_chain! { |
| 456 | + if let ExprKind::Block(block, _) = then.kind; |
| 457 | + if let [statement, ..] = block.stmts; |
| 458 | + if let StmtKind::Expr(call_assert_failed) |
| 459 | + | StmtKind::Semi(call_assert_failed) = statement.kind; |
| 460 | + if let ExprKind::Call(_, args_assert_failed) = call_assert_failed.kind; |
| 461 | + if args_assert_failed.len() >= 1; |
| 462 | + if let ExprKind::Call(_, [arg, ..]) = args_assert_failed[0].kind; |
| 463 | + if let Some(format_arg_expn) = FormatArgsExpn::parse(&arg); |
| 464 | + then { |
| 465 | + return Some(Self { |
| 466 | + first_assert_argument: condition, |
| 467 | + second_assert_argument: None, |
| 468 | + format_arg: Some(format_arg_expn), // FIXME actually parse the aguments |
| 469 | + }); |
| 470 | + } |
| 471 | + else{ |
| 472 | + return Some(Self { |
| 473 | + first_assert_argument: condition, |
| 474 | + second_assert_argument: None, |
| 475 | + format_arg: None, |
| 476 | + }); |
| 477 | + } |
| 478 | + } |
457 | 479 | }
|
458 | 480 | }
|
459 | 481 |
|
@@ -516,19 +538,49 @@ impl<'tcx> AssertExpn<'tcx> {
|
516 | 538 | None
|
517 | 539 | }
|
518 | 540 |
|
519 |
| - /// Gives the argument as a vector |
520 |
| - pub fn argument_vector(&self) -> Vec<&'tcx Expr<'tcx>> { |
| 541 | + /// Gives the argument in the comparaison as a vector leaving the format |
| 542 | + pub fn assert_arguments(&self) -> Vec<&'tcx Expr<'tcx>> { |
521 | 543 | let mut expr_vec = vec![self.first_assert_argument];
|
522 | 544 | if let Some(sec_agr) = self.second_assert_argument {
|
523 | 545 | expr_vec.push(sec_agr);
|
524 | 546 | }
|
525 |
| - if let Some(ref format_arg) = self.format_arg { |
526 |
| - expr_vec.push(format_arg.format_string); |
527 |
| - for arg in &format_arg.value_args { |
528 |
| - expr_vec.push(arg) |
| 547 | + expr_vec |
| 548 | + } |
| 549 | + |
| 550 | + /// Gives the argument passed to the macro as a string |
| 551 | + pub fn all_arguments_string( |
| 552 | + &self, |
| 553 | + cx: &LateContext<'_>, |
| 554 | + applicability: &mut Applicability, |
| 555 | + ) -> Vec<Cow<'static, str>> { |
| 556 | + let mut vec_arg = vec![snippet_with_applicability( |
| 557 | + cx, |
| 558 | + self.first_assert_argument.span, |
| 559 | + "..", |
| 560 | + applicability, |
| 561 | + )]; |
| 562 | + if let Some(sec_agr) = self.second_assert_argument { |
| 563 | + vec_arg.push(snippet_with_applicability(cx, sec_agr.span, "..", applicability)); |
| 564 | + } |
| 565 | + vec_arg.append(&mut self.format_arguments(cx, applicability)); |
| 566 | + vec_arg |
| 567 | + } |
| 568 | + |
| 569 | + /// Returns only the format agruments |
| 570 | + pub fn format_arguments(&self, cx: &LateContext<'_>, applicability: &mut Applicability) -> Vec<Cow<'static, str>> { |
| 571 | + let mut vec_arg = vec![]; |
| 572 | + if let Some(ref fmt_arg) = self.format_arg { |
| 573 | + vec_arg.push(snippet_with_applicability( |
| 574 | + cx, |
| 575 | + fmt_arg.format_string_span, |
| 576 | + "..", |
| 577 | + applicability, |
| 578 | + )); |
| 579 | + for arg in &fmt_arg.value_args { |
| 580 | + vec_arg.push(snippet_with_applicability(cx, arg.span, "..", applicability)); |
529 | 581 | }
|
530 | 582 | }
|
531 |
| - expr_vec |
| 583 | + vec_arg |
532 | 584 | }
|
533 | 585 | }
|
534 | 586 |
|
@@ -566,8 +618,6 @@ impl FormatExpn<'tcx> {
|
566 | 618 |
|
567 | 619 | /// A parsed `format_args!` expansion
|
568 | 620 | pub struct FormatArgsExpn<'tcx> {
|
569 |
| - /// The fist argument, the fromat string, as an expr |
570 |
| - pub format_string: &'tcx Expr<'tcx>, |
571 | 621 | /// Span of the first argument, the format string
|
572 | 622 | pub format_string_span: Span,
|
573 | 623 | /// Values passed after the format string
|
@@ -629,7 +679,6 @@ impl FormatArgsExpn<'tcx> {
|
629 | 679 | .collect();
|
630 | 680 | then {
|
631 | 681 | Some(FormatArgsExpn {
|
632 |
| - format_string:strs_ref, |
633 | 682 | format_string_span: strs_ref.span,
|
634 | 683 | value_args,
|
635 | 684 | format_string_parts,
|
|
0 commit comments