diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index 0355eccc397e5..7d6827f0af653 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -683,8 +683,6 @@ void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { std::tuple Priority; }; - removeDuplicatedDiagnosticsOfAliasCheckers(); - // Compute error sizes. std::vector Sizes; std::vector< @@ -760,9 +758,12 @@ struct LessClangTidyError { const tooling::DiagnosticMessage &M1 = LHS.Message; const tooling::DiagnosticMessage &M2 = RHS.Message; - return std::tie(M1.FilePath, M1.FileOffset, LHS.DiagnosticName, - M1.Message) < - std::tie(M2.FilePath, M2.FileOffset, RHS.DiagnosticName, M2.Message); + // Having DiagnosticName (i.e. the check name) last means sorting + // using this predicate puts duplicate diagnostics into consecutive runs, a + // property which removeDuplicatedDiagnosticsOfAliasCheckers() relies on. + return std::tie(M1.FilePath, M1.FileOffset, M1.Message, + LHS.DiagnosticName) < + std::tie(M2.FilePath, M2.FileOffset, M2.Message, RHS.DiagnosticName); } }; struct EqualClangTidyError { @@ -778,43 +779,38 @@ std::vector ClangTidyDiagnosticConsumer::take() { llvm::stable_sort(Errors, LessClangTidyError()); Errors.erase(llvm::unique(Errors, EqualClangTidyError()), Errors.end()); - if (RemoveIncompatibleErrors) + if (RemoveIncompatibleErrors) { + removeDuplicatedDiagnosticsOfAliasCheckers(); removeIncompatibleErrors(); + } return std::move(Errors); } -namespace { -struct LessClangTidyErrorWithoutDiagnosticName { - bool operator()(const ClangTidyError *LHS, const ClangTidyError *RHS) const { - const tooling::DiagnosticMessage &M1 = LHS->Message; - const tooling::DiagnosticMessage &M2 = RHS->Message; - - return std::tie(M1.FilePath, M1.FileOffset, M1.Message) < - std::tie(M2.FilePath, M2.FileOffset, M2.Message); - } -}; -} // end anonymous namespace - void ClangTidyDiagnosticConsumer::removeDuplicatedDiagnosticsOfAliasCheckers() { - using UniqueErrorSet = - std::set; - UniqueErrorSet UniqueErrors; + if (Errors.size() <= 1) + return; - auto IT = Errors.begin(); - while (IT != Errors.end()) { - ClangTidyError &Error = *IT; - const std::pair Inserted = - UniqueErrors.insert(&Error); + static constexpr auto AreDuplicates = [](const ClangTidyError &E1, + const ClangTidyError &E2) { + const tooling::DiagnosticMessage &M1 = E1.Message; + const tooling::DiagnosticMessage &M2 = E2.Message; + return std::tie(M1.FilePath, M1.FileOffset, M1.Message) == + std::tie(M2.FilePath, M2.FileOffset, M2.Message); + }; + auto LastUniqueErrorIt = Errors.begin(); + for (ClangTidyError &Error : llvm::drop_begin(Errors, 1)) { + ClangTidyError &ExistingError = *LastUniqueErrorIt; // Unique error, we keep it and move along. - if (Inserted.second) { - ++IT; + if (!AreDuplicates(Error, ExistingError)) { + ++LastUniqueErrorIt; + if (&*LastUniqueErrorIt != &Error) // Avoid self-moves. + *LastUniqueErrorIt = std::move(Error); } else { - ClangTidyError &ExistingError = **Inserted.first; const llvm::StringMap &CandidateFix = Error.Message.Fix; const llvm::StringMap &ExistingFix = - (*Inserted.first)->Message.Fix; + ExistingError.Message.Fix; if (CandidateFix != ExistingFix) { // In case of a conflict, don't suggest any fix-it. @@ -833,7 +829,7 @@ void ClangTidyDiagnosticConsumer::removeDuplicatedDiagnosticsOfAliasCheckers() { // Since it is the same error, we should take it as alias and remove it. ExistingError.EnabledDiagnosticAliases.emplace_back(Error.DiagnosticName); - IT = Errors.erase(IT); } } + Errors.erase(std::next(LastUniqueErrorIt), Errors.end()); }