Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -469,34 +469,40 @@ } // Build events from error intervals. - std::vector Events; + std::map> FileEvents; for (unsigned I = 0; I < Errors.size(); ++I) { for (const auto &Replace : Errors[I].Fix) { unsigned Begin = Replace.getOffset(); unsigned End = Begin + Replace.getLength(); + const std::string &FilePath = Replace.getFilePath(); // FIXME: Handle empty intervals, such as those from insertions. if (Begin == End) continue; - Events.push_back(Event(Begin, End, Event::ET_Begin, I, Sizes[I])); - Events.push_back(Event(Begin, End, Event::ET_End, I, Sizes[I])); + FileEvents[FilePath].push_back( + Event(Begin, End, Event::ET_Begin, I, Sizes[I])); + FileEvents[FilePath].push_back( + Event(Begin, End, Event::ET_End, I, Sizes[I])); } } - std::sort(Events.begin(), Events.end()); - // Sweep. std::vector Apply(Errors.size(), true); - int OpenIntervals = 0; - for (const auto &Event : Events) { - if (Event.Type == Event::ET_End) - --OpenIntervals; - // This has to be checked after removing the interval from the count if it - // is an end event, or before adding it if it is a begin event. - if (OpenIntervals != 0) - Apply[Event.ErrorId] = false; - if (Event.Type == Event::ET_Begin) - ++OpenIntervals; + for (auto &FileAndEvents : FileEvents) { + std::vector &Events = FileAndEvents.second; + // Sweep. + std::sort(Events.begin(), Events.end()); + int OpenIntervals = 0; + for (const auto &Event : Events) { + if (Event.Type == Event::ET_End) + --OpenIntervals; + // This has to be checked after removing the interval from the count if it + // is an end event, or before adding it if it is a begin event. + if (OpenIntervals != 0) + Apply[Event.ErrorId] = false; + if (Event.Type == Event::ET_Begin) + ++OpenIntervals; + } + assert(OpenIntervals == 0 && "Amount of begin/end points doesn't match"); } - assert(OpenIntervals == 0 && "Amount of begin/end points doesn't match"); for (unsigned I = 0; I < Errors.size(); ++I) { if (!Apply[I]) { Index: test/clang-tidy/Inputs/overlapping/o.h =================================================================== --- /dev/null +++ test/clang-tidy/Inputs/overlapping/o.h @@ -0,0 +1,9 @@ +// run: ! clang-tidy -checks=-*,llvm-include-order -header-filter=.* %s \ +// run: -- -isystem %S/Inputs/Headers -I %S/Inputs/overlapping | \ +// run: grep "note: this fix will not be applied because it overlaps with another fix" + +#include "b.h" +#include "a.h" + +// The comments above are there to match the offset of the #include with the +// offset of the #includes in the .cpp file. Index: test/clang-tidy/overlapping.cpp =================================================================== --- /dev/null +++ test/clang-tidy/overlapping.cpp @@ -0,0 +1,10 @@ +// RUN: ! clang-tidy -checks=-*,llvm-include-order -header-filter=.* %s \ +// RUN: -- -isystem %S/Inputs/Headers -I %S/Inputs/overlapping | \ +// RUN: grep "note: this fix will not be applied because it overlaps with another fix" + +#include +#include "o.h" + +// Test that clang-tidy takes into account in which file we are doing the +// replacements to determine if they overlap or not. In the file "o.h" there is +// a similar error at the same file offset, but they do not overlap.