diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -10,6 +10,7 @@ #include "../clang-tidy/ClangTidyCheck.h" #include "../clang-tidy/ClangTidyDiagnosticConsumer.h" #include "../clang-tidy/ClangTidyModuleRegistry.h" +#include "../clang-tidy/GlobList.h" #include "AST.h" #include "Compiler.h" #include "Config.h" @@ -45,6 +46,7 @@ #include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -282,6 +284,59 @@ } } +// Turns a clang-tidy glob list into a BitVector that can be used to build the +// necessary checks efficiently. +class CachedFactories { + std::vector( + llvm::StringRef, tidy::ClangTidyContext *)>>> + AllChecks; + std::mutex Guard; + llvm::StringMap CachedGlobs; + + llvm::BitVector &getCachedValue(StringRef CheckGlobString) { + std::lock_guard LG(Guard); + auto It = CachedGlobs.find(CheckGlobString); + if (It != CachedGlobs.end()) + return It->getValue(); + // On the first time we see a glob, we construct the representation and + // cache it for the next time. In most projects there would only ever be one + // unique Glob. + tidy::GlobList Glob(CheckGlobString); + llvm::BitVector IsEnabled(AllChecks.size(), false); + for (size_t I = 0, E = AllChecks.size(); I != E; ++I) { + if (Glob.contains(AllChecks[I].first)) + IsEnabled.set(I); + } + return CachedGlobs.insert_or_assign(CheckGlobString, std::move(IsEnabled)) + .first->getValue(); + } + +public: + CachedFactories() { + tidy::ClangTidyCheckFactories CTFactories; + for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) + E.instantiate()->addCheckFactories(CTFactories); + for (const auto &Item : CTFactories) { + AllChecks.emplace_back(Item.getKey(), Item.getValue()); + } + } + + std::vector> + createChecks(tidy::ClangTidyContext *Context) { + if (!Context->getOptions().Checks) + return {}; + llvm::BitVector &IsEnabled = getCachedValue(*Context->getOptions().Checks); + std::vector> Result; + Result.reserve(IsEnabled.size()); + for (unsigned CheckID : IsEnabled.set_bits()) { + Result.push_back( + AllChecks[CheckID].second(AllChecks[CheckID].first, Context)); + } + return Result; + } +}; + } // namespace llvm::Optional @@ -410,15 +465,13 @@ // diagnostics. if (PreserveDiags) { trace::Span Tracer("ClangTidyInit"); - tidy::ClangTidyCheckFactories CTFactories; - for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) - E.instantiate()->addCheckFactories(CTFactories); + static CachedFactories Factory; CTContext.emplace(std::make_unique( tidy::ClangTidyGlobalOptions(), ClangTidyOpts)); CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); CTContext->setASTContext(&Clang->getASTContext()); CTContext->setCurrentFile(Filename); - CTChecks = CTFactories.createChecks(CTContext.getPointer()); + CTChecks = Factory.createChecks(CTContext.getPointer()); llvm::erase_if(CTChecks, [&](const auto &Check) { return !Check->isLanguageVersionSupported(CTContext->getLangOpts()); });