diff --git a/src/Clazy.h b/src/Clazy.h --- a/src/Clazy.h +++ b/src/Clazy.h @@ -55,8 +55,11 @@ ClazyASTAction(); protected: + /// @note This function is reentrant std::unique_ptr CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef) override; + /// @note This function is reentrant bool ParseArgs(const clang::CompilerInstance &ci, const std::vector &args_) override; + void PrintHelp(llvm::raw_ostream &ros, HelpMode = HelpMode_Normal); void PrintAnchorHeader(llvm::raw_ostream &ro, RegisteredCheck::List &checks); private: diff --git a/src/Clazy.cpp b/src/Clazy.cpp --- a/src/Clazy.cpp +++ b/src/Clazy.cpp @@ -37,6 +37,7 @@ #include "clang/AST/ParentMap.h" #include +#include #include #include #include @@ -150,6 +151,11 @@ std::unique_ptr ClazyASTAction::CreateASTConsumer(CompilerInstance &, llvm::StringRef) { + // NOTE: This method needs to be kept reentrant (but not necessarily thread-safe) + // Might be called from multiple threads via libclang, each thread operates on a different instance though + + std::lock_guard lock(CheckManager::lock()); + auto astConsumer = new ClazyASTConsumer(m_context); CheckBase::List createdChecks = m_checkManager->createChecks(m_checks, m_context); for (CheckBase *check : createdChecks) { @@ -161,6 +167,9 @@ bool ClazyASTAction::ParseArgs(const CompilerInstance &ci, const std::vector &args_) { + // NOTE: This method needs to be kept reentrant (but not necessarily thread-safe) + // Might be called from multiple threads via libclang, each thread operates on a different instance though + std::vector args = args_; if (parseArgument("help", args)) { @@ -193,7 +202,10 @@ // This argument is for debugging purposes const bool dbgPrintRequestedChecks = parseArgument("print-requested-checks", args); - m_checks = m_checkManager->requestedChecks(m_context, args); + { + std::lock_guard lock(CheckManager::lock()); + m_checks = m_checkManager->requestedChecks(m_context, args); + } if (args.size() > 1) { // Too many arguments. @@ -262,7 +274,9 @@ void ClazyASTAction::PrintHelp(llvm::raw_ostream &ros, HelpMode helpMode) { + std::lock_guard lock(CheckManager::lock()); RegisteredCheck::List checks = m_checkManager->availableChecks(MaxCheckLevel); + clazy_std::sort(checks, checkLessThanByLevel); if (helpMode == HelpMode_AnchorHeader) { diff --git a/src/checkmanager.h b/src/checkmanager.h --- a/src/checkmanager.h +++ b/src/checkmanager.h @@ -31,6 +31,7 @@ #include #include +#include #include struct CLAZYLIB_EXPORT RegisteredFixIt { @@ -77,8 +78,15 @@ class CLAZYLIB_EXPORT CheckManager { public: + /** + * @note You must hold the CheckManager lock when operating on the instance + * + * @sa lock() + */ static CheckManager *instance(); + static std::mutex &lock() { return m_lock; } + int registerCheck(const std::string &name, const std::string &className, CheckLevel level, const FactoryFunction &, RegisteredCheck::Options = RegisteredCheck::Option_None); int registerFixIt(int id, const std::string &fititName, const std::string &checkName); @@ -106,6 +114,8 @@ private: CheckManager(); + static std::mutex m_lock; + bool checkExists(const std::string &name) const; RegisteredCheck::List checksForLevel(int level) const; bool isReservedCheckName(const std::string &name) const; diff --git a/src/checkmanager.cpp b/src/checkmanager.cpp --- a/src/checkmanager.cpp +++ b/src/checkmanager.cpp @@ -36,6 +36,8 @@ static const char * s_fixitNamePrefix = "fix-"; static const char * s_levelPrefix = "level"; +std::mutex CheckManager::m_lock; + CheckManager::CheckManager() { m_registeredChecks.reserve(100);