diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -11,9 +11,17 @@ #include "Logger.h" #include "index/Relation.h" #include "index/SymbolOrigin.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Index/IndexingAction.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/STLExtras.h" +#include +#include #include namespace clang { @@ -113,6 +121,40 @@ IncludeGraph &IG; }; +/// Returns an ASTConsumer that wraps \p Inner and additionally instructs the +/// parser to skip bodies of functions in the files that should not be +/// processed. +static std::unique_ptr +skipProcessedFunctions(std::unique_ptr Inner, + std::function ShouldIndexFile) { + class SkipProcessedFunctions : public ASTConsumer { + public: + SkipProcessedFunctions(std::function FileFilter) + : ShouldIndexFile(std::move(FileFilter)), Context(nullptr) { + assert(this->ShouldIndexFile); + } + + void Initialize(ASTContext &Context) override { this->Context = &Context; } + bool shouldSkipFunctionBody(Decl *D) override { + assert(Context && "Initialize() was never called."); + auto &SM = Context->getSourceManager(); + auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation())); + if (!FID.isValid()) + return false; + return !ShouldIndexFile(FID); + } + + private: + std::function ShouldIndexFile; + const ASTContext *Context; + }; + std::vector> Consumers; + Consumers.push_back( + std::make_unique(ShouldIndexFile)); + Consumers.push_back(std::move(Inner)); + return std::make_unique(std::move(Consumers)); +} + // Wraps the index action and reports index data after each translation unit. class IndexAction : public WrapperFrontendAction { public: @@ -137,7 +179,9 @@ if (IncludeGraphCallback != nullptr) CI.getPreprocessor().addPPCallbacks( std::make_unique(CI.getSourceManager(), IG)); - return WrapperFrontendAction::CreateASTConsumer(CI, InFile); + return skipProcessedFunctions( + WrapperFrontendAction::CreateASTConsumer(CI, InFile), + [this](FileID FID) { return Collector->shouldIndexFile(FID); }); } bool BeginInvocation(CompilerInstance &CI) override { @@ -147,6 +191,10 @@ // Avoids some analyses too. Set in two places as we're late to the party. CI.getDiagnosticOpts().IgnoreWarnings = true; CI.getDiagnostics().setIgnoreAllWarnings(true); + // Instruct the parser to ask our ASTConsumer if it should skip function + // bodies. The ASTConsumer will take care of skipping only functions inside + // the files that we have already processed. + CI.getFrontendOpts().SkipFunctionBodies = true; return WrapperFrontendAction::BeginInvocation(CI); } diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h --- a/clang-tools-extra/clangd/index/SymbolCollector.h +++ b/clang-tools-extra/clangd/index/SymbolCollector.h @@ -112,6 +112,11 @@ RefSlab takeRefs() { return std::move(Refs).build(); } RelationSlab takeRelations() { return std::move(Relations).build(); } + /// Returns true if we are interested in references and declarations from \p + /// FID. If this function return false, bodies of functions inside those files + /// will be skipped to decrease indexing time. + bool shouldIndexFile(FileID FID); + void finish() override; private: diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -147,17 +147,6 @@ CreatePosition(TokLoc.getLocWithOffset(TokenLength))}; } -bool shouldIndexFile(const SourceManager &SM, FileID FID, - const SymbolCollector::Options &Opts, - llvm::DenseMap *FilesToIndexCache) { - if (!Opts.FileFilter) - return true; - auto I = FilesToIndexCache->try_emplace(FID); - if (I.second) - I.first->second = Opts.FileFilter(SM, FID); - return I.first->second; -} - // Return the symbol location of the token at \p TokLoc. llvm::Optional getTokenLocation(SourceLocation TokLoc, const SourceManager &SM, @@ -410,7 +399,7 @@ S.SymInfo = index::getSymbolInfoForMacro(*MI); std::string FileURI; // FIXME: use the result to filter out symbols. - shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache); + shouldIndexFile(SM.getFileID(Loc)); if (auto DeclLoc = getTokenLocation(DefLoc, SM, Opts, PP->getLangOpts(), FileURI)) S.CanonicalDeclaration = *DeclLoc; @@ -540,7 +529,7 @@ for (const auto &LocAndRole : It.second) { auto FileID = SM.getFileID(LocAndRole.first); // FIXME: use the result to filter out references. - shouldIndexFile(SM, FileID, Opts, &FilesToIndexCache); + shouldIndexFile(FileID); if (auto FileURI = GetURI(FileID)) { auto Range = getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts()); @@ -590,7 +579,7 @@ auto Loc = spellingLocIfSpelled(findName(&ND), SM); assert(Loc.isValid() && "Invalid source location for NamedDecl"); // FIXME: use the result to filter out symbols. - shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache); + shouldIndexFile(SM.getFileID(Loc)); if (auto DeclLoc = getTokenLocation(Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI)) S.CanonicalDeclaration = *DeclLoc; @@ -650,7 +639,7 @@ const auto &SM = ND.getASTContext().getSourceManager(); auto Loc = spellingLocIfSpelled(findName(&ND), SM); // FIXME: use the result to filter out symbols. - shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache); + shouldIndexFile(SM.getFileID(Loc)); if (auto DefLoc = getTokenLocation(Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI)) S.Definition = *DefLoc; @@ -742,5 +731,14 @@ return false; } +bool SymbolCollector::shouldIndexFile(FileID FID) { + if (!Opts.FileFilter) + return true; + auto I = FilesToIndexCache.try_emplace(FID); + if (I.second) + I.first->second = Opts.FileFilter(ASTCtx->getSourceManager(), FID); + return I.first->second; +} + } // namespace clangd } // namespace clang