12#include "clang-include-cleaner/Record.h"
27#include "clang/AST/ASTContext.h"
28#include "clang/Index/IndexingAction.h"
29#include "clang/Index/IndexingOptions.h"
30#include "clang/Lex/Preprocessor.h"
31#include "llvm/ADT/DenseMap.h"
32#include "llvm/ADT/STLExtras.h"
33#include "llvm/ADT/StringMap.h"
34#include "llvm/ADT/StringRef.h"
47 llvm::ArrayRef<Decl *> DeclsToIndex,
48 const MainFileMacros *MacroRefsToIndex,
49 const include_cleaner::PragmaIncludes &PI,
50 bool IsIndexMainAST, llvm::StringRef Version,
51 bool CollectMainFileRefs) {
63 index::IndexingOptions IndexOpts;
65 IndexOpts.SystemSymbolFilter =
66 index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly;
68 IndexOpts.IndexFunctionLocals =
true;
76 IndexOpts.IndexMacrosInPreprocessor =
true;
82 Collector.setPreprocessor(PP);
83 index::indexTopLevelDecls(
AST, PP, DeclsToIndex, Collector, IndexOpts);
85 Collector.handleMacros(*MacroRefsToIndex);
87 const auto &SM =
AST.getSourceManager();
88 const auto MainFileEntry = SM.getFileEntryRefForID(SM.getMainFileID());
90 std::string(MainFileEntry ? MainFileEntry->getName() :
"");
92 auto Syms = Collector.takeSymbols();
93 auto Refs = Collector.takeRefs();
94 auto Relations = Collector.takeRelations();
96 vlog(
"indexed {0} AST for {1} version {2}:\n"
97 " symbol slab: {3} symbols, {4} bytes\n"
98 " ref slab: {5} symbols, {6} refs, {7} bytes\n"
99 " relations slab: {8} relations, {9} bytes",
100 IsIndexMainAST ?
"file" :
"preamble",
FileName, Version, Syms.size(),
101 Syms.bytes(), Refs.size(), Refs.numRefs(), Refs.bytes(),
102 Relations.size(), Relations.bytes());
103 return std::make_tuple(std::move(Syms), std::move(Refs),
104 std::move(Relations));
112 auto Entry = IG.try_emplace(URI).first;
114 Node = FullGraph.lookup(
Entry->getKey());
118 for (
auto &Include :
Node.DirectIncludes) {
119 auto I = IG.try_emplace(Include).first;
120 I->getValue().URI = I->getKey();
121 Include = I->getKey();
128 : Index(std::move(Input)) {
130 llvm::DenseMap<SymbolID, FileShard *> SymbolIDToFile;
134 for (
const auto &S : *Index.
Symbols) {
135 auto It = Shards.try_emplace(S.CanonicalDeclaration.FileURI);
136 It.first->getValue().Symbols.insert(&S);
137 SymbolIDToFile[S.ID] = &It.first->getValue();
140 S.Definition.FileURI != S.CanonicalDeclaration.FileURI) {
141 auto It = Shards.try_emplace(S.Definition.FileURI);
142 It.first->getValue().Symbols.insert(&S);
148 for (
const auto &SymRefs : *Index.
Refs) {
149 for (
const auto &R : SymRefs.second) {
150 const auto It = Shards.try_emplace(R.Location.FileURI);
151 It.first->getValue().Refs.insert(&R);
152 RefToSymID[&R] = SymRefs.first;
165 FileShard *SubjectFile = SymbolIDToFile.lookup(R.Subject);
166 FileShard *ObjectFile = SymbolIDToFile.lookup(R.Object);
168 SubjectFile->Relations.insert(&R);
169 if (ObjectFile && ObjectFile != SubjectFile)
170 ObjectFile->Relations.insert(&R);
175 const auto &FullGraph = *Index.
Sources;
176 for (
const auto &It : FullGraph) {
177 auto ShardIt = Shards.try_emplace(It.first());
178 ShardIt.first->getValue().IG = getSubGraph(It.first(), FullGraph);
185 std::vector<PathRef> Result;
186 Result.reserve(Shards.size());
187 for (
auto Key : Shards.keys())
188 Result.push_back(
Key);
192std::optional<IndexFileIn>
194 auto It = Shards.find(Uri);
195 if (It == Shards.end())
199 IF.
Sources = It->getValue().IG;
203 for (
const auto *S : It->getValue().Symbols)
205 IF.
Symbols = std::move(SymB).build();
208 for (
const auto *
Ref : It->getValue().Refs) {
209 auto SID = RefToSymID.lookup(
Ref);
212 IF.
Refs = std::move(RefB).build();
215 for (
const auto *Rel : It->getValue().Relations) {
220 return std::move(IF);
225 AST.getASTContext(),
AST.getPreprocessor(),
AST.getLocalTopLevelDecls(),
226 &
AST.getMacros(),
AST.getPragmaIncludes(),
227 true,
AST.version(),
true);
232 const include_cleaner::PragmaIncludes &PI) {
233 std::vector<Decl *> DeclsToIndex(
234 AST.getTranslationUnitDecl()->decls().begin(),
235 AST.getTranslationUnitDecl()->decls().end());
236 return indexSymbols(
AST, PP, DeclsToIndex,
243 : IdxContents(IdxContents) {}
246 std::unique_ptr<SymbolSlab>
Symbols,
247 std::unique_ptr<RefSlab> Refs,
248 std::unique_ptr<RelationSlab> Relations,
249 bool CountReferences) {
250 std::lock_guard<std::mutex> Lock(Mutex);
253 SymbolsSnapshot.erase(
Key);
257 RefsSnapshot.erase(
Key);
259 RefSlabAndCountReferences Item;
260 Item.CountReferences = CountReferences;
261 Item.Slab = std::move(Refs);
262 RefsSnapshot[
Key] = std::move(Item);
265 RelationsSnapshot.erase(
Key);
267 RelationsSnapshot[
Key] = std::move(Relations);
270std::unique_ptr<SymbolIndex>
273 std::vector<std::shared_ptr<SymbolSlab>> SymbolSlabs;
274 std::vector<std::shared_ptr<RefSlab>> RefSlabs;
275 std::vector<std::shared_ptr<RelationSlab>> RelationSlabs;
276 llvm::StringSet<> Files;
277 std::vector<RefSlab *> MainFileRefs;
279 std::lock_guard<std::mutex> Lock(Mutex);
280 for (
const auto &FileAndSymbols : SymbolsSnapshot) {
281 SymbolSlabs.push_back(FileAndSymbols.second);
282 Files.insert(FileAndSymbols.first());
284 for (
const auto &FileAndRefs : RefsSnapshot) {
285 RefSlabs.push_back(FileAndRefs.second.Slab);
286 Files.insert(FileAndRefs.first());
287 if (FileAndRefs.second.CountReferences)
288 MainFileRefs.push_back(RefSlabs.back().get());
290 for (
const auto &FileAndRelations : RelationsSnapshot) {
291 Files.insert(FileAndRelations.first());
292 RelationSlabs.push_back(FileAndRelations.second);
296 *Version = this->Version;
298 std::vector<const Symbol *> AllSymbols;
299 std::vector<Symbol> SymsStorage;
300 switch (DuplicateHandle) {
302 llvm::DenseMap<SymbolID, Symbol> Merged;
303 for (
const auto &Slab : SymbolSlabs) {
304 for (
const auto &Sym : *Slab) {
305 assert(Sym.References == 0 &&
306 "Symbol with non-zero references sent to FileSymbols");
307 auto I = Merged.try_emplace(Sym.ID, Sym);
309 I.first->second =
mergeSymbol(I.first->second, Sym);
312 for (
const RefSlab *Refs : MainFileRefs)
313 for (
const auto &Sym : *Refs) {
314 auto It = Merged.find(Sym.first);
316 if (It == Merged.end())
318 It->getSecond().References += Sym.second.size();
320 SymsStorage.reserve(Merged.size());
321 for (
auto &Sym : Merged) {
322 SymsStorage.push_back(std::move(Sym.second));
323 AllSymbols.push_back(&SymsStorage.back());
328 llvm::DenseSet<SymbolID> AddedSymbols;
329 for (
const auto &Slab : SymbolSlabs)
330 for (
const auto &Sym : *Slab) {
331 assert(Sym.References == 0 &&
332 "Symbol with non-zero references sent to FileSymbols");
333 if (AddedSymbols.insert(Sym.ID).second)
334 AllSymbols.push_back(&Sym);
340 std::vector<Ref> RefsStorage;
341 llvm::DenseMap<SymbolID, llvm::ArrayRef<Ref>> AllRefs;
343 llvm::DenseMap<SymbolID, llvm::SmallVector<Ref, 4>> MergedRefs;
345 for (
const auto &
RefSlab : RefSlabs)
346 for (
const auto &Sym : *
RefSlab) {
347 MergedRefs[Sym.first].append(Sym.second.begin(), Sym.second.end());
348 Count += Sym.second.size();
350 RefsStorage.reserve(Count);
351 AllRefs.reserve(MergedRefs.size());
352 for (
auto &Sym : MergedRefs) {
353 auto &SymRefs = Sym.second;
356 llvm::copy(SymRefs, back_inserter(RefsStorage));
359 llvm::ArrayRef<Ref>(&RefsStorage[RefsStorage.size() - SymRefs.size()],
364 std::vector<Relation> AllRelations;
367 AllRelations.push_back(R);
372 llvm::sort(AllRelations);
373 AllRelations.erase(std::unique(AllRelations.begin(), AllRelations.end()),
377 RefsStorage.size() *
sizeof(
Ref) + SymsStorage.size() *
sizeof(
Symbol);
378 for (
const auto &Slab : SymbolSlabs)
379 StorageSize += Slab->bytes();
380 for (
const auto &
RefSlab : RefSlabs)
386 return std::make_unique<MemIndex>(
387 llvm::make_pointee_range(AllSymbols), std::move(AllRefs),
388 std::move(AllRelations), std::move(Files), IdxContents,
389 std::make_tuple(std::move(SymbolSlabs), std::move(RefSlabs),
390 std::move(RefsStorage), std::move(SymsStorage)),
393 return std::make_unique<dex::Dex>(
394 llvm::make_pointee_range(AllSymbols), std::move(AllRefs),
395 std::move(AllRelations), std::move(Files), IdxContents,
396 std::make_tuple(std::move(SymbolSlabs), std::move(RefSlabs),
397 std::move(RefsStorage), std::move(SymsStorage)),
400 llvm_unreachable(
"Unknown clangd::IndexType");
404 std::lock_guard<std::mutex> Lock(Mutex);
405 for (
const auto &SymSlab : SymbolsSnapshot) {
406 MT.
detail(SymSlab.first())
410 for (
const auto &
RefSlab : RefsSnapshot) {
415 for (
const auto &RelSlab : RelationsSnapshot) {
416 MT.
detail(RelSlab.first())
425 PreambleIndex(std::make_unique<
MemIndex>()),
427 MainFileIndex(std::make_unique<
MemIndex>()) {}
432 auto IF = ShardedIndex.
getShard(Uri);
437 Uri, std::make_unique<SymbolSlab>(std::move(*IF->
Symbols)),
438 std::make_unique<RefSlab>(),
439 std::make_unique<RelationSlab>(std::move(*IF->
Relations)),
442 size_t IndexVersion = 0;
446 std::lock_guard<std::mutex> Lock(UpdateIndexMu);
447 if (IndexVersion <= PreambleIndexVersion) {
451 PreambleIndexVersion = IndexVersion;
452 PreambleIndex.
reset(std::move(NewIndex));
454 "Build dynamic index for header symbols with estimated memory usage of "
461 ASTContext &
AST, Preprocessor &PP,
462 const include_cleaner::PragmaIncludes &PI) {
473 std::make_unique<SymbolSlab>(std::move(std::get<0>(Contents))),
474 std::make_unique<RefSlab>(std::move(std::get<1>(Contents))),
475 std::make_unique<RelationSlab>(std::move(std::get<2>(Contents))),
477 size_t IndexVersion = 0;
481 std::lock_guard<std::mutex> Lock(UpdateIndexMu);
482 if (IndexVersion <= MainIndexVersion) {
486 MainIndexVersion = IndexVersion;
487 MainFileIndex.
reset(std::move(NewIndex));
489 "Build dynamic index for main-file symbols with estimated memory usage "
501 MT.
child(
"main_file")
This defines Dex - a symbol index implementation based on query iterators over symbol tokens,...
::clang::DynTypedNode Node
SymbolCollector::Options CollectorOpts
void updatePreamble(PathRef Path, llvm::StringRef Version, ASTContext &AST, Preprocessor &PP, const include_cleaner::PragmaIncludes &PI)
Update preamble symbols of file Path with all declarations in AST and macros in PP.
void profile(MemoryTree &MT) const
void updateMain(PathRef Path, ParsedAST &AST)
Update symbols and references from main file Path with indexMainDecls.
FileSymbols(IndexContents IdxContents)
void update(llvm::StringRef Key, std::unique_ptr< SymbolSlab > Symbols, std::unique_ptr< RefSlab > Refs, std::unique_ptr< RelationSlab > Relations, bool CountReferences)
Updates all slabs associated with the Key.
std::unique_ptr< SymbolIndex > buildIndex(IndexType, DuplicateHandling DuplicateHandle=DuplicateHandling::PickOne, size_t *Version=nullptr)
The index keeps the slabs alive.
void profile(MemoryTree &MT) const
Values in a Context are indexed by typed keys.
MemIndex is a naive in-memory index suitable for a small set of symbols.
Stores and provides access to parsed AST.
RefSlab::Builder is a mutable container that can 'freeze' to RefSlab.
void insert(const SymbolID &ID, const Ref &S)
Adds a ref to the slab. Deep copy: Strings will be owned by the slab.
An efficient structure of storing large set of symbol references in memory.
RelationSlab::Builder is a mutable container that can 'freeze' to RelationSlab.
void insert(const Relation &R)
Adds a relation to the slab.
void reset(std::unique_ptr< SymbolIndex >)
size_t estimateMemoryUsage() const override
Returns estimated size of index (in bytes).
SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
void insert(const Symbol &S)
Adds a symbol, overwriting any existing one with the same ID.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
IndexType
Select between in-memory index implementations, which have tradeoffs.
IndexContents
Describes what data is covered by an index.
std::string Path
A typedef to represent a file path.
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
void vlog(const char *Fmt, Ts &&... Vals)
static const char * toString(OffsetEncoding OE)
SlabTuple indexMainDecls(ParsedAST &AST)
Retrieves symbols and refs of local top level decls in AST (i.e.
std::tuple< SymbolSlab, RefSlab, RelationSlab > SlabTuple
DuplicateHandling
How to handle duplicated symbols across multiple files.
SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST, Preprocessor &PP, const include_cleaner::PragmaIncludes &PI)
Index declarations from AST and macros from PP that are declared in included headers.
llvm::StringMap< IncludeGraphNode > IncludeGraph
@ Type
An inlay hint that for a type annotation.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Takes slabs coming from a TU (multiple files) and shards them per declaration location.
std::vector< llvm::StringRef > getAllSources() const
Returns uris for all files that has a shard.
std::optional< IndexFileIn > getShard(llvm::StringRef Uri) const
Generates index shard for the Uri.
FileShardedIndex(IndexFileIn Input)
HintPath is used to convert file URIs stored in symbols into absolute paths.
std::optional< RelationSlab > Relations
std::optional< SymbolSlab > Symbols
std::optional< RefSlab > Refs
std::optional< tooling::CompileCommand > Cmd
std::optional< IncludeGraph > Sources
A tree that can be used to represent memory usage of nested components while preserving the hierarchy...
void addUsage(size_t Increment)
Increases size of current node by Increment.
MemoryTree & child(llvm::StringLiteral Name)
No copy of the Name.
MemoryTree & detail(llvm::StringRef Name)
Makes a copy of the Name in detailed mode, returns current node otherwise.
Represents a symbol occurrence in the source file.
bool CollectMacro
Collect macros.
RefKind RefFilter
The symbol ref kinds that will be collected.
bool StoreAllDocumentation
If set to true, SymbolCollector will collect doc for all symbols.
bool CollectMainFileRefs
Collect references to main-file symbols.
bool CollectReserved
Collect symbols with reserved names, like __Vector_base.
const include_cleaner::PragmaIncludes * PragmaIncludes
If set, this is used to map symbol #include path to a potentially different #include path specified b...
The class presents a C++ symbol, e.g.