@@ -571,6 +571,11 @@ static int dumpConfig(bool IsSTDIN) {
571
571
return 0 ;
572
572
}
573
573
574
+ using String = SmallString<128 >;
575
+ static String IgnoreDir; // Directory of .clang-format-ignore file.
576
+ static StringRef PrevDir; // Directory of previous `FilePath`.
577
+ static SmallVector<String> Patterns; // Patterns in .clang-format-ignore file.
578
+
574
579
// Check whether `FilePath` is ignored according to the nearest
575
580
// .clang-format-ignore file based on the rules below:
576
581
// - A blank line is skipped.
@@ -586,45 +591,65 @@ static bool isIgnored(StringRef FilePath) {
586
591
if (!is_regular_file (FilePath))
587
592
return false ;
588
593
589
- using namespace llvm ::sys::path ;
590
- SmallString< 128 > Path, AbsPath{FilePath};
594
+ String Path ;
595
+ String AbsPath{FilePath};
591
596
597
+ using namespace llvm ::sys::path;
592
598
make_absolute (AbsPath);
593
599
remove_dots (AbsPath, /* remove_dot_dot=*/ true );
594
600
595
- StringRef IgnoreDir{AbsPath};
596
- do {
597
- IgnoreDir = parent_path (IgnoreDir);
598
- if (IgnoreDir.empty ())
601
+ if (StringRef Dir{parent_path (AbsPath)}; PrevDir != Dir) {
602
+ PrevDir = Dir;
603
+
604
+ for (;;) {
605
+ Path = Dir;
606
+ append (Path, " .clang-format-ignore" );
607
+ if (is_regular_file (Path))
608
+ break ;
609
+ Dir = parent_path (Dir);
610
+ if (Dir.empty ())
611
+ return false ;
612
+ }
613
+
614
+ IgnoreDir = convert_to_slash (Dir);
615
+
616
+ std::ifstream IgnoreFile{Path.c_str ()};
617
+ if (!IgnoreFile.good ())
599
618
return false ;
600
619
601
- Path = IgnoreDir;
602
- append (Path, " .clang-format-ignore" );
603
- } while (!is_regular_file (Path));
620
+ Patterns.clear ();
604
621
605
- std::ifstream IgnoreFile{Path.c_str ()};
606
- if (!IgnoreFile.good ())
607
- return false ;
622
+ for (std::string Line; std::getline (IgnoreFile, Line);) {
623
+ if (const auto Pattern{StringRef{Line}.trim ()};
624
+ // Skip empty and comment lines.
625
+ !Pattern.empty () && Pattern[0 ] != ' #' ) {
626
+ Patterns.push_back (Pattern);
627
+ }
628
+ }
629
+ }
608
630
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 ;
631
+ if (IgnoreDir.empty ())
632
+ return false ;
614
633
615
- const bool IsNegated = Pattern[0 ] == ' !' ;
634
+ const auto Pathname{convert_to_slash (AbsPath)};
635
+ for (const auto &Pat : Patterns) {
636
+ const bool IsNegated = Pat[0 ] == ' !' ;
637
+ StringRef Pattern{Pat};
616
638
if (IsNegated)
617
639
Pattern = Pattern.drop_front ();
618
640
619
641
if (Pattern.empty ())
620
642
continue ;
621
643
622
644
Pattern = Pattern.ltrim ();
645
+
646
+ // `Pattern` is relative to `IgnoreDir` unless it starts with a slash.
647
+ // This doesn't support patterns containing drive names (e.g. `C:`).
623
648
if (Pattern[0 ] != ' /' ) {
624
- Path = convert_to_slash ( IgnoreDir) ;
649
+ Path = IgnoreDir;
625
650
append (Path, Style ::posix, Pattern);
626
651
remove_dots (Path, /* remove_dot_dot=*/ true , Style ::posix);
627
- Pattern = Path. str () ;
652
+ Pattern = Path;
628
653
}
629
654
630
655
if (clang::format::matchFilePath (Pattern, Pathname) == !IsNegated)
0 commit comments