|
12 | 12 | ///
|
13 | 13 | //===----------------------------------------------------------------------===//
|
14 | 14 |
|
| 15 | +#include "../../lib/Format/MatchFilePath.h" |
15 | 16 | #include "clang/Basic/Diagnostic.h"
|
16 | 17 | #include "clang/Basic/DiagnosticOptions.h"
|
17 | 18 | #include "clang/Basic/FileManager.h"
|
@@ -570,6 +571,69 @@ static int dumpConfig(bool IsSTDIN) {
|
570 | 571 | return 0;
|
571 | 572 | }
|
572 | 573 |
|
| 574 | +// Check whether `FilePath` is ignored according to the nearest |
| 575 | +// .clang-format-ignore file based on the rules below: |
| 576 | +// - A blank line is skipped. |
| 577 | +// - Leading and trailing spaces of a line are trimmed. |
| 578 | +// - A line starting with a hash (`#`) is a comment. |
| 579 | +// - A non-comment line is a single pattern. |
| 580 | +// - The slash (`/`) is used as the directory separator. |
| 581 | +// - A pattern is relative to the directory of the .clang-format-ignore file (or |
| 582 | +// the root directory if the pattern starts with a slash). |
| 583 | +// - A pattern is negated if it starts with a bang (`!`). |
| 584 | +static bool isIgnored(StringRef FilePath) { |
| 585 | + using namespace llvm::sys::fs; |
| 586 | + if (!is_regular_file(FilePath)) |
| 587 | + return false; |
| 588 | + |
| 589 | + using namespace llvm::sys::path; |
| 590 | + SmallString<128> Path, AbsPath{FilePath}; |
| 591 | + |
| 592 | + make_absolute(AbsPath); |
| 593 | + remove_dots(AbsPath, /*remove_dot_dot=*/true); |
| 594 | + |
| 595 | + StringRef IgnoreDir{AbsPath}; |
| 596 | + do { |
| 597 | + IgnoreDir = parent_path(IgnoreDir); |
| 598 | + if (IgnoreDir.empty()) |
| 599 | + return false; |
| 600 | + |
| 601 | + Path = IgnoreDir; |
| 602 | + append(Path, ".clang-format-ignore"); |
| 603 | + } while (!is_regular_file(Path)); |
| 604 | + |
| 605 | + std::ifstream IgnoreFile{Path.c_str()}; |
| 606 | + if (!IgnoreFile.good()) |
| 607 | + return false; |
| 608 | + |
| 609 | + const auto Pathname = convert_to_slash(AbsPath); |
| 610 | + for (std::string Line; std::getline(IgnoreFile, Line);) { |
| 611 | + auto Pattern = StringRef(Line).trim(); |
| 612 | + if (Pattern.empty() || Pattern[0] == '#') |
| 613 | + continue; |
| 614 | + |
| 615 | + const bool IsNegated = Pattern[0] == '!'; |
| 616 | + if (IsNegated) |
| 617 | + Pattern = Pattern.drop_front(); |
| 618 | + |
| 619 | + if (Pattern.empty()) |
| 620 | + continue; |
| 621 | + |
| 622 | + Pattern = Pattern.ltrim(); |
| 623 | + if (Pattern[0] != '/') { |
| 624 | + Path = convert_to_slash(IgnoreDir); |
| 625 | + append(Path, Style::posix, Pattern); |
| 626 | + remove_dots(Path, /*remove_dot_dot=*/true, Style::posix); |
| 627 | + Pattern = Path.str(); |
| 628 | + } |
| 629 | + |
| 630 | + if (clang::format::matchFilePath(Pattern, Pathname) == !IsNegated) |
| 631 | + return true; |
| 632 | + } |
| 633 | + |
| 634 | + return false; |
| 635 | +} |
| 636 | + |
573 | 637 | int main(int argc, const char **argv) {
|
574 | 638 | llvm::InitLLVM X(argc, argv);
|
575 | 639 |
|
@@ -618,11 +682,14 @@ int main(int argc, const char **argv) {
|
618 | 682 | unsigned FileNo = 1;
|
619 | 683 | bool Error = false;
|
620 | 684 | for (const auto &FileName : FileNames) {
|
| 685 | + const bool IsSTDIN = FileName == "-"; |
| 686 | + if (!IsSTDIN && isIgnored(FileName)) |
| 687 | + continue; |
621 | 688 | if (Verbose) {
|
622 | 689 | errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
|
623 | 690 | << FileName << "\n";
|
624 | 691 | }
|
625 |
| - Error |= clang::format::format(FileName, FileName == "-"); |
| 692 | + Error |= clang::format::format(FileName, IsSTDIN); |
626 | 693 | }
|
627 | 694 | return Error ? 1 : 0;
|
628 | 695 | }
|
0 commit comments