Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -230,12 +230,13 @@ /// \param StoreCheckProfile If provided, and EnableCheckProfile is true, /// the profile will not be output to stderr, but will instead be stored /// as a JSON file in the specified directory. -void runClangTidy(clang::tidy::ClangTidyContext &Context, - const tooling::CompilationDatabase &Compilations, - ArrayRef InputFiles, - llvm::IntrusiveRefCntPtr BaseFS, - bool EnableCheckProfile = false, - llvm::StringRef StoreCheckProfile = StringRef()); +std::vector +runClangTidy(clang::tidy::ClangTidyContext &Context, + const tooling::CompilationDatabase &Compilations, + ArrayRef InputFiles, + llvm::IntrusiveRefCntPtr BaseFS, + bool EnableCheckProfile = false, + llvm::StringRef StoreCheckProfile = StringRef()); // FIXME: This interface will need to be significantly extended to be useful. // FIXME: Implement confidence levels for displaying/fixing errors. @@ -243,7 +244,8 @@ /// \brief Displays the found \p Errors to the users. If \p Fix is true, \p /// Errors containing fixes are automatically applied and reformatted. If no /// clang-format configuration file is found, the given \P FormatStyle is used. -void handleErrors(ClangTidyContext &Context, bool Fix, +void handleErrors(llvm::ArrayRef Diags, + ClangTidyContext &Context, bool Fix, unsigned &WarningsAsErrorsCount, llvm::IntrusiveRefCntPtr BaseFS); Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -500,11 +500,12 @@ return Factory.getCheckOptions(); } -void runClangTidy(clang::tidy::ClangTidyContext &Context, - const CompilationDatabase &Compilations, - ArrayRef InputFiles, - llvm::IntrusiveRefCntPtr BaseFS, - bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) { +std::vector +runClangTidy(clang::tidy::ClangTidyContext &Context, + const CompilationDatabase &Compilations, + ArrayRef InputFiles, + llvm::IntrusiveRefCntPtr BaseFS, + bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) { ClangTool Tool(Compilations, InputFiles, std::make_shared(), BaseFS); @@ -586,9 +587,11 @@ ActionFactory Factory(Context); Tool.run(&Factory); + return DiagConsumer.take(); } -void handleErrors(ClangTidyContext &Context, bool Fix, +void handleErrors(llvm::ArrayRef Diags, + ClangTidyContext &Context, bool Fix, unsigned &WarningsAsErrorsCount, llvm::IntrusiveRefCntPtr BaseFS) { ErrorReporter Reporter(Context, Fix, BaseFS); @@ -598,7 +601,7 @@ if (!InitialWorkingDir) llvm::report_fatal_error("Cannot get current working path."); - for (const ClangTidyError &Error : Context.getErrors()) { + for (const ClangTidyError &Error : Diags) { if (!Error.BuildDirectory.empty()) { // By default, the working directory of file system is the current // clang-tidy running directory. Index: clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tidy/ClangTidyDiagnosticConsumer.h @@ -160,12 +160,6 @@ /// counters. const ClangTidyStats &getStats() const { return Stats; } - /// \brief Returns all collected errors. - ArrayRef getErrors() const { return Errors; } - - /// \brief Clears collected errors. - void clearErrors() { Errors.clear(); } - /// \brief Control profile collection in clang-tidy. void setEnableProfiling(bool Profile); bool getEnableProfiling() const { return Profile; } @@ -203,7 +197,6 @@ /// \brief Store an \p Error. void storeError(const ClangTidyError &Error); - std::vector Errors; DiagnosticsEngine *DiagEngine; std::unique_ptr OptionsProvider; @@ -243,13 +236,16 @@ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override; - /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext. + // Finalizes currently buffered errors. void finish() override; + // Retrieve the diagnostics that were captured. + // Non-finalized errors are ignored. (FIXME: why? backwards compatibility?) + std::vector take() { return std::move(FinalizedErrors); } + private: void finalizeLastError(); - - void removeIncompatibleErrors(SmallVectorImpl &Errors) const; + void removeIncompatibleErrors(); /// \brief Returns the \c HeaderFilter constructed for the options set in the /// context. @@ -263,7 +259,8 @@ ClangTidyContext &Context; bool RemoveIncompatibleErrors; std::unique_ptr Diags; - SmallVector Errors; + std::vector Errors; + std::vector FinalizedErrors; std::unique_ptr HeaderFilter; bool LastErrorRelatesToUserCode; bool LastErrorPassesLineFilter; Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -259,11 +259,6 @@ return WarningAsErrorFilter->contains(CheckName); } -/// \brief Store a \c ClangTidyError. -void ClangTidyContext::storeError(const ClangTidyError &Error) { - Errors.push_back(Error); -} - StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const { llvm::DenseMap::const_iterator I = CheckNamesByDiagnosticID.find(DiagnosticID); @@ -534,8 +529,7 @@ return HeaderFilter.get(); } -void ClangTidyDiagnosticConsumer::removeIncompatibleErrors( - SmallVectorImpl &Errors) const { +void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line // algorithm over these sets of intervals. @@ -673,18 +667,14 @@ }; } // end anonymous namespace -// Flushes the internal diagnostics buffer to the ClangTidyContext. void ClangTidyDiagnosticConsumer::finish() { finalizeLastError(); std::sort(Errors.begin(), Errors.end(), LessClangTidyError()); Errors.erase(std::unique(Errors.begin(), Errors.end(), EqualClangTidyError()), Errors.end()); - if (RemoveIncompatibleErrors) - removeIncompatibleErrors(Errors); - - for (const ClangTidyError &Error : Errors) - Context.storeError(Error); + removeIncompatibleErrors(); + std::move(Errors.begin(), Errors.end(), std::back_inserter(FinalizedErrors)); Errors.clear(); } Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -422,9 +422,9 @@ ClangTidyContext Context(std::move(OwningOptionsProvider), AllowEnablingAnalyzerAlphaCheckers); - runClangTidy(Context, OptionsParser.getCompilations(), PathList, BaseFS, - EnableCheckProfile, ProfilePrefix); - ArrayRef Errors = Context.getErrors(); + std::vector Errors = + runClangTidy(Context, OptionsParser.getCompilations(), PathList, BaseFS, + EnableCheckProfile, ProfilePrefix); bool FoundErrors = llvm::find_if(Errors, [](const ClangTidyError &E) { return E.DiagLevel == ClangTidyError::Error; }) != Errors.end(); @@ -434,7 +434,7 @@ unsigned WErrorCount = 0; // -fix-errors implies -fix. - handleErrors(Context, (FixErrors || Fix) && !DisableFixes, WErrorCount, + handleErrors(Errors, Context, (FixErrors || Fix) && !DisableFixes, WErrorCount, BaseFS); if (!ExportFixes.empty() && !Errors.empty()) { Index: unittests/clang-tidy/ClangTidyTest.h =================================================================== --- unittests/clang-tidy/ClangTidyTest.h +++ unittests/clang-tidy/ClangTidyTest.h @@ -118,7 +118,7 @@ Invocation.setDiagnosticConsumer(&DiagConsumer); if (!Invocation.run()) { std::string ErrorText; - for (const auto &Error : Context.getErrors()) { + for (const auto &Error : DiagConsumer.take()) { ErrorText += Error.Message.Message + "\n"; } llvm::report_fatal_error(ErrorText); @@ -126,7 +126,8 @@ DiagConsumer.finish(); tooling::Replacements Fixes; - for (const ClangTidyError &Error : Context.getErrors()) { + auto Diags = DiagConsumer.take(); + for (const ClangTidyError &Error : Diags) { for (const auto &FileAndFixes : Error.Fix) { for (const auto &Fix : FileAndFixes.second) { auto Err = Fixes.add(Fix); @@ -139,7 +140,7 @@ } } if (Errors) - *Errors = Context.getErrors(); + *Errors = std::move(Diags); auto Result = tooling::applyAllReplacements(Code, Fixes); if (!Result) { // FIXME: propogate the error.