Optional<Expected<tooling::AtomicChanges>> Result;
};
+} // namespace
-class UpdateFileIndex : public ParsingCallbacks {
+/// Manages dynamic index for open files. Each file might contribute two sets
+/// of symbols to the dynamic index: symbols from the preamble and symbols
+/// from the file itself. Those have different lifetimes and we merge results
+/// from both
+class ClangdServer::DynamicIndex : public ParsingCallbacks {
public:
- UpdateFileIndex(FileIndex *FileIdx) : FileIdx(FileIdx) {}
+ DynamicIndex(std::vector<std::string> URISchemes)
+ : PreambleIdx(URISchemes), MainFileIdx(URISchemes),
+ MergedIndex(mergeIndex(&MainFileIdx, &PreambleIdx)) {}
+
+ SymbolIndex &index() const { return *MergedIndex; }
void onPreambleAST(PathRef Path, ASTContext &Ctx,
std::shared_ptr<clang::Preprocessor> PP) override {
- if (FileIdx)
- FileIdx->update(Path, &Ctx, std::move(PP));
+ PreambleIdx.update(Path, &Ctx, PP, /*TopLevelDecls=*/llvm::None);
}
void onMainAST(PathRef Path, ParsedAST &AST) override {
- // FIXME: merge results from the main file into the index too.
+
+ MainFileIdx.update(Path, &AST.getASTContext(), AST.getPreprocessorPtr(),
+ AST.getLocalTopLevelDecls());
}
private:
- FileIndex *FileIdx;
+ FileIndex PreambleIdx;
+ FileIndex MainFileIdx;
+ /// Merged view into both indexes. Merges are performed in a similar manner
+ /// to the merges of dynamic and static index.
+ std::unique_ptr<SymbolIndex> MergedIndex;
};
-} // namespace
-
ClangdServer::Options ClangdServer::optsForTest() {
ClangdServer::Options Opts;
Opts.UpdateDebounce = std::chrono::steady_clock::duration::zero(); // Faster!
: CDB(CDB), DiagConsumer(DiagConsumer), FSProvider(FSProvider),
ResourceDir(Opts.ResourceDir ? Opts.ResourceDir->str()
: getStandardResourceDir()),
- FileIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex(Opts.URISchemes)
- : nullptr),
- FileIdxUpdater(llvm::make_unique<UpdateFileIndex>(FileIdx.get())),
+ DynamicIdx(Opts.BuildDynamicSymbolIndex
+ ? new DynamicIndex(Opts.URISchemes)
+ : nullptr),
PCHs(std::make_shared<PCHContainerOperations>()),
// Pass a callback into `WorkScheduler` to extract symbols from a newly
// parsed file and rebuild the file index synchronously each time an AST
// FIXME(ioeric): this can be slow and we may be able to index on less
// critical paths.
WorkScheduler(Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory,
- *FileIdxUpdater, Opts.UpdateDebounce,
- Opts.RetentionPolicy) {
- if (FileIdx && Opts.StaticIndex) {
- MergedIndex = mergeIndex(FileIdx.get(), Opts.StaticIndex);
+ DynamicIdx ? *DynamicIdx : noopParsingCallbacks(),
+ Opts.UpdateDebounce, Opts.RetentionPolicy) {
+ if (DynamicIdx && Opts.StaticIndex) {
+ MergedIndex = mergeIndex(&DynamicIdx->index(), Opts.StaticIndex);
Index = MergedIndex.get();
- } else if (FileIdx)
- Index = FileIdx.get();
+ } else if (DynamicIdx)
+ Index = &DynamicIdx->index();
else if (Opts.StaticIndex)
Index = Opts.StaticIndex;
else
Index = nullptr;
}
+// Destructor has to be in .cpp file to see the definition of
+// ClangdServer::DynamicIndex.
+ClangdServer::~ClangdServer() = default;
+
void ClangdServer::setRootPath(PathRef RootPath) {
auto FS = FSProvider.getFileSystem();
auto Status = FS->status(RootPath);
/// synchronize access to shared state.
ClangdServer(GlobalCompilationDatabase &CDB, FileSystemProvider &FSProvider,
DiagnosticsConsumer &DiagConsumer, const Options &Opts);
+ ~ClangdServer();
/// Set the root path of the workspace.
void setRootPath(PathRef RootPath);
formatCode(llvm::StringRef Code, PathRef File,
ArrayRef<tooling::Range> Ranges);
+ class DynamicIndex;
typedef uint64_t DocVersion;
void consumeDiagnostics(PathRef File, DocVersion Version,
Path ResourceDir;
// The index used to look up symbols. This could be:
// - null (all index functionality is optional)
- // - the dynamic index owned by ClangdServer (FileIdx)
+ // - the dynamic index owned by ClangdServer (DynamicIdx)
// - the static index passed to the constructor
// - a merged view of a static and dynamic index (MergedIndex)
SymbolIndex *Index;
- // If present, an up-to-date of symbols in open files. Read via Index.
- std::unique_ptr<FileIndex> FileIdx;
- /// Callbacks responsible for updating FileIdx.
- std::unique_ptr<ParsingCallbacks> FileIdxUpdater;
- // If present, a merged view of FileIdx and an external index. Read via Index.
+ /// If present, an up-to-date of symbols in open files. Read via Index.
+ std::unique_ptr<DynamicIndex> DynamicIdx;
+ // If present, a merged view of DynamicIdx and an external index. Read via
+ // Index.
std::unique_ptr<SymbolIndex> MergedIndex;
// If set, this represents the workspace path.
llvm::Optional<std::string> RootPath;
//===----------------------------------------------------------------------===//
#include "FileIndex.h"
-#include "SymbolCollector.h"
#include "../Logger.h"
+#include "SymbolCollector.h"
#include "clang/Index/IndexingAction.h"
#include "clang/Lex/Preprocessor.h"
namespace clangd {
SymbolSlab indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
+ llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls,
llvm::ArrayRef<std::string> URISchemes) {
SymbolCollector::Options CollectorOpts;
// FIXME(ioeric): we might also want to collect include headers. We would need
index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly;
IndexOpts.IndexFunctionLocals = false;
- std::vector<const Decl *> TopLevelDecls(
- AST.getTranslationUnitDecl()->decls().begin(),
- AST.getTranslationUnitDecl()->decls().end());
- index::indexTopLevelDecls(AST, TopLevelDecls, Collector, IndexOpts);
+ std::vector<Decl *> DeclsToIndex;
+ if (TopLevelDecls)
+ DeclsToIndex.assign(TopLevelDecls->begin(), TopLevelDecls->end());
+ else
+ DeclsToIndex.assign(AST.getTranslationUnitDecl()->decls().begin(),
+ AST.getTranslationUnitDecl()->decls().end());
+
+ index::indexTopLevelDecls(AST, DeclsToIndex, Collector, IndexOpts);
return Collector.takeSymbols();
}
}
void FileIndex::update(PathRef Path, ASTContext *AST,
- std::shared_ptr<Preprocessor> PP) {
+ std::shared_ptr<Preprocessor> PP,
+ llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls) {
if (!AST) {
FSymbols.update(Path, nullptr);
} else {
assert(PP);
auto Slab = llvm::make_unique<SymbolSlab>();
- *Slab = indexAST(*AST, PP, URISchemes);
+ *Slab = indexAST(*AST, PP, TopLevelDecls, URISchemes);
FSymbols.update(Path, std::move(Slab));
}
auto Symbols = FSymbols.allSymbols();
/// nullptr, this removes all symbols in the file.
/// If \p AST is not null, \p PP cannot be null and it should be the
/// preprocessor that was used to build \p AST.
- void update(PathRef Path, ASTContext *AST, std::shared_ptr<Preprocessor> PP);
+ /// If \p TopLevelDecls is set, only these decls are indexed. Otherwise, all
+ /// top level decls obtained from \p AST are indexed.
+ void
+ update(PathRef Path, ASTContext *AST, std::shared_ptr<Preprocessor> PP,
+ llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls = llvm::None);
bool
fuzzyFind(const FuzzyFindRequest &Req,
/// Retrieves namespace and class level symbols in \p AST.
/// Exposed to assist in unit tests.
/// If URISchemes is empty, the default schemes in SymbolCollector will be used.
-SymbolSlab indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
- llvm::ArrayRef<std::string> URISchemes = {});
+/// If \p TopLevelDecls is set, only these decls are indexed. Otherwise, all top
+/// level decls obtained from \p AST are indexed.
+SymbolSlab
+indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
+ llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls = llvm::None,
+ llvm::ArrayRef<std::string> URISchemes = {});
} // namespace clangd
} // namespace clang