<div dir="ltr">Thanks Mikael,<div><br></div><div>66b54d586fa73499714e2bfef3cedffeabb08f34 should fix this.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Apr 17, 2020 at 2:42 PM Mikael Holmén <<a href="mailto:mikael.holmen@ericsson.com">mikael.holmen@ericsson.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Kadir,<br>
<br>
I noticed in our buildbots that run with sanitizers that we got a new<br>
complaint with this commit. It's still there on current top-of-tree now<br>
so the fixes you pushed after this patch doesn't seem to address this<br>
one:<br>
<br>
==89727==ERROR: LeakSanitizer: detected memory leaks<br>
<br>
Direct leak of 136 byte(s) in 1 object(s) allocated from:<br>
#0 0x5b9838 in operator new(unsigned long)<br>
/repo/uabkaka/tmp/llvm/projects/compiler-<br>
rt/lib/asan/asan_new_delete.cc:106<br>
#1 0xc50879 in make_unique<clang::clangd::RefSlab,<br>
clang::clangd::RefSlab><br>
/proj/flexasic/app/llvm/8.0/bin/../include/c++/v1/memory:3132:28<br>
#2 0xc50879 in refSlab /repo/bbiswjenk/fem023-<br>
eiffel003/workspace/llvm/llvm-master-sanitize-asan/llvm/build-all-<br>
asan/../../clang-tools-extra/clangd/unittests/FileIndexTests.cpp:87<br>
#3 0xc50879 in clang::clangd::(anonymous<br>
namespace)::FileShardedIndexTest_Sharding_Test::TestBody()<br>
/repo/bbiswjenk/fem023-eiffel003/workspace/llvm/llvm-master-sanitize-<br>
asan/llvm/build-all-asan/../../clang-tools-<br>
extra/clangd/unittests/FileIndexTests.cpp:535<br>
#4 0x1620190 in HandleExceptionsInMethodIfSupported<testing::Test,<br>
void> /repo/bbiswjenk/fem023-eiffel003/workspace/llvm/llvm-master-<br>
sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/src/gtest.cc<br>
#5 0x1620190 in testing::Test::Run() /repo/bbiswjenk/fem023-<br>
eiffel003/workspace/llvm/llvm-master-sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/src/gtest.cc:2474<br>
#6 0x1623875 in testing::TestInfo::Run() /repo/bbiswjenk/fem023-<br>
eiffel003/workspace/llvm/llvm-master-sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/src/gtest.cc:2656:11<br>
#7 0x1624cf0 in testing::TestCase::Run() /repo/bbiswjenk/fem023-<br>
eiffel003/workspace/llvm/llvm-master-sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/src/gtest.cc:2774:28<br>
#8 0x1643714 in testing::internal::UnitTestImpl::RunAllTests()<br>
/repo/bbiswjenk/fem023-eiffel003/workspace/llvm/llvm-master-sanitize-<br>
asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/src/gtest.cc:4649:43<br>
#9 0x16428c0 in<br>
HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,<br>
bool> /repo/bbiswjenk/fem023-eiffel003/workspace/llvm/llvm-master-<br>
sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/src/gtest.cc<br>
#10 0x16428c0 in testing::UnitTest::Run() /repo/bbiswjenk/fem023-<br>
eiffel003/workspace/llvm/llvm-master-sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/src/gtest.cc:4257<br>
#11 0x16048f0 in RUN_ALL_TESTS /repo/bbiswjenk/fem023-<br>
eiffel003/workspace/llvm/llvm-master-sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/googletest/include/gtest/gtest.h:2233:46<br>
#12 0x16048f0 in main /repo/bbiswjenk/fem023-<br>
eiffel003/workspace/llvm/llvm-master-sanitize-asan/llvm/build-all-<br>
asan/../utils/unittest/UnitTestMain/TestMain.cpp:50<br>
#13 0x7f558b333544 in __libc_start_main (/lib64/libc.so.6+0x22544)<br>
<br>
SUMMARY: AddressSanitizer: 136 byte(s) leaked in 1 allocation(s).<br>
<br>
/Mikael<br>
<br>
On Wed, 2020-04-15 at 00:15 -0700, Kadir Cetinkaya via cfe-commits<br>
wrote:<br>
> Author: Kadir Cetinkaya<br>
> Date: 2020-04-15T09:10:10+02:00<br>
> New Revision: dffa9dfbda56820c02e357ad34c24ce8759b4d26<br>
> <br>
> URL: <br>
> <a href="https://protect2.fireeye.com/v1/url?k=1ed901c9-4253d508-1ed94152-863d9bcb726f-37cce004cef08ce5&q=1&e=d51603fa-ef7d-4c66-99fd-b868e84ed659&u=https%3A%2F%2Fgithub.com%2Fllvm%2Fllvm-project%2Fcommit%2Fdffa9dfbda56820c02e357ad34c24ce8759b4d26" rel="noreferrer" target="_blank">https://protect2.fireeye.com/v1/url?k=1ed901c9-4253d508-1ed94152-863d9bcb726f-37cce004cef08ce5&q=1&e=d51603fa-ef7d-4c66-99fd-b868e84ed659&u=https%3A%2F%2Fgithub.com%2Fllvm%2Fllvm-project%2Fcommit%2Fdffa9dfbda56820c02e357ad34c24ce8759b4d26</a><br>
> DIFF: <br>
> <a href="https://protect2.fireeye.com/v1/url?k=27955bfa-7b1f8f3b-27951b61-863d9bcb726f-307938d8468e38e8&q=1&e=d51603fa-ef7d-4c66-99fd-b868e84ed659&u=https%3A%2F%2Fgithub.com%2Fllvm%2Fllvm-project%2Fcommit%2Fdffa9dfbda56820c02e357ad34c24ce8759b4d26.diff" rel="noreferrer" target="_blank">https://protect2.fireeye.com/v1/url?k=27955bfa-7b1f8f3b-27951b61-863d9bcb726f-307938d8468e38e8&q=1&e=d51603fa-ef7d-4c66-99fd-b868e84ed659&u=https%3A%2F%2Fgithub.com%2Fllvm%2Fllvm-project%2Fcommit%2Fdffa9dfbda56820c02e357ad34c24ce8759b4d26.diff</a><br>
> <br>
> LOG: [clangd] Shard preamble symbols in dynamic index<br>
> <br>
> Summary:<br>
> This reduces memory usage by dynamic index from more than 400MB to<br>
> 32MB<br>
> when all files in clang-tools-extra/clangd/*.cpp are active in<br>
> clangd.<br>
> <br>
> Reviewers: sammccall<br>
> <br>
> Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95,<br>
> cfe-commits<br>
> <br>
> Tags: #clang<br>
> <br>
> Differential Revision: <a href="https://reviews.llvm.org/D77732" rel="noreferrer" target="_blank">https://reviews.llvm.org/D77732</a><br>
> <br>
> Added: <br>
> <br>
> <br>
> Modified: <br>
> clang-tools-extra/clangd/index/Background.cpp<br>
> clang-tools-extra/clangd/index/FileIndex.cpp<br>
> clang-tools-extra/clangd/index/FileIndex.h<br>
> clang-tools-extra/clangd/index/SymbolCollector.cpp<br>
> clang-tools-extra/clangd/unittests/FileIndexTests.cpp<br>
> clang-tools-extra/clangd/unittests/TestTU.cpp<br>
> <br>
> Removed: <br>
> <br>
> <br>
> <br>
> #####################################################################<br>
> ###########<br>
> diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-<br>
> tools-extra/clangd/index/Background.cpp<br>
> index 1c26dd48093e..4c5719d0526c 100644<br>
> --- a/clang-tools-extra/clangd/index/Background.cpp<br>
> +++ b/clang-tools-extra/clangd/index/Background.cpp<br>
> @@ -61,51 +61,6 @@ namespace clang {<br>
> namespace clangd {<br>
> namespace {<br>
> <br>
> -// Resolves URI to file paths with cache.<br>
> -class URIToFileCache {<br>
> -public:<br>
> - URIToFileCache(llvm::StringRef HintPath) : HintPath(HintPath) {}<br>
> -<br>
> - llvm::StringRef resolve(llvm::StringRef FileURI) {<br>
> - auto I = URIToPathCache.try_emplace(FileURI);<br>
> - if (I.second) {<br>
> - auto Path = URI::resolve(FileURI, HintPath);<br>
> - if (!Path) {<br>
> - elog("Failed to resolve URI {0}: {1}", FileURI,<br>
> Path.takeError());<br>
> - assert(false && "Failed to resolve URI");<br>
> - return "";<br>
> - }<br>
> - I.first->second = *Path;<br>
> - }<br>
> - return I.first->second;<br>
> - }<br>
> -<br>
> -private:<br>
> - std::string HintPath;<br>
> - llvm::StringMap<std::string> URIToPathCache;<br>
> -};<br>
> -<br>
> -// We keep only the node "U" and its edges. Any node other than "U"<br>
> will be<br>
> -// empty in the resultant graph.<br>
> -IncludeGraph getSubGraph(const URI &U, const IncludeGraph<br>
> &FullGraph) {<br>
> - IncludeGraph IG;<br>
> -<br>
> - std::string FileURI = U.toString();<br>
> - auto Entry = IG.try_emplace(FileURI).first;<br>
> - auto &Node = Entry->getValue();<br>
> - Node = FullGraph.lookup(Entry->getKey());<br>
> - Node.URI = Entry->getKey();<br>
> -<br>
> - // URIs inside nodes must point into the keys of the same<br>
> IncludeGraph.<br>
> - for (auto &Include : Node.DirectIncludes) {<br>
> - auto I = IG.try_emplace(Include).first;<br>
> - I->getValue().URI = I->getKey();<br>
> - Include = I->getKey();<br>
> - }<br>
> -<br>
> - return IG;<br>
> -}<br>
> -<br>
> // We cannot use vfs->makeAbsolute because Cmd.FileName is either<br>
> absolute or<br>
> // relative to Cmd.Directory, which might not be the same as current<br>
> working<br>
> // directory.<br>
> @@ -219,108 +174,44 @@ void BackgroundIndex::update(<br>
> llvm::StringRef MainFile, IndexFileIn Index,<br>
> const llvm::StringMap<ShardVersion> &ShardVersionsSnapshot,<br>
> bool HadErrors) {<br>
> - // Partition symbols/references into files.<br>
> - struct File {<br>
> - llvm::DenseSet<const Symbol *> Symbols;<br>
> - llvm::DenseSet<const Ref *> Refs;<br>
> - llvm::DenseSet<const Relation *> Relations;<br>
> - FileDigest Digest;<br>
> - };<br>
> - llvm::StringMap<File> Files;<br>
> - URIToFileCache URICache(MainFile);<br>
> + llvm::StringMap<FileDigest> FilesToUpdate;<br>
> for (const auto &IndexIt : *Index.Sources) {<br>
> const auto &IGN = IndexIt.getValue();<br>
> // Note that sources do not contain any information regarding<br>
> missing<br>
> // headers, since we don't even know what absolute path they<br>
> should fall in.<br>
> - const auto AbsPath = URICache.resolve(IGN.URI);<br>
> + auto AbsPath = llvm::cantFail(URI::resolve(IGN.URI, MainFile),<br>
> + "Failed to resovle URI");<br>
> const auto DigestIt = ShardVersionsSnapshot.find(AbsPath);<br>
> // File has <br>
> diff erent contents, or indexing was successful this time.<br>
> if (DigestIt == ShardVersionsSnapshot.end() ||<br>
> DigestIt->getValue().Digest != IGN.Digest ||<br>
> (DigestIt->getValue().HadErrors && !HadErrors))<br>
> - Files.try_emplace(AbsPath).first->getValue().Digest =<br>
> IGN.Digest;<br>
> - }<br>
> - // This map is used to figure out where to store relations.<br>
> - llvm::DenseMap<SymbolID, File *> SymbolIDToFile;<br>
> - for (const auto &Sym : *Index.Symbols) {<br>
> - if (Sym.CanonicalDeclaration) {<br>
> - auto DeclPath =<br>
> URICache.resolve(Sym.CanonicalDeclaration.FileURI);<br>
> - const auto FileIt = Files.find(DeclPath);<br>
> - if (FileIt != Files.end()) {<br>
> - FileIt->second.Symbols.insert(&Sym);<br>
> - SymbolIDToFile[Sym.ID] = &FileIt->second;<br>
> - }<br>
> - }<br>
> - // For symbols with <br>
> diff erent declaration and definition locations, we store<br>
> - // the full symbol in both the header file and the<br>
> implementation file, so<br>
> - // that merging can tell the preferred symbols (from canonical<br>
> headers) from<br>
> - // other symbols (e.g. forward declarations).<br>
> - if (Sym.Definition &&<br>
> - Sym.Definition.FileURI != Sym.CanonicalDeclaration.FileURI)<br>
> {<br>
> - auto DefPath = URICache.resolve(Sym.Definition.FileURI);<br>
> - const auto FileIt = Files.find(DefPath);<br>
> - if (FileIt != Files.end())<br>
> - FileIt->second.Symbols.insert(&Sym);<br>
> - }<br>
> - }<br>
> - llvm::DenseMap<const Ref *, SymbolID> RefToIDs;<br>
> - for (const auto &SymRefs : *Index.Refs) {<br>
> - for (const auto &R : SymRefs.second) {<br>
> - auto Path = URICache.resolve(R.Location.FileURI);<br>
> - const auto FileIt = Files.find(Path);<br>
> - if (FileIt != Files.end()) {<br>
> - auto &F = FileIt->getValue();<br>
> - RefToIDs[&R] = SymRefs.first;<br>
> - F.Refs.insert(&R);<br>
> - }<br>
> - }<br>
> - }<br>
> - for (const auto &Rel : *Index.Relations) {<br>
> - const auto FileIt = SymbolIDToFile.find(Rel.Subject);<br>
> - if (FileIt != SymbolIDToFile.end())<br>
> - FileIt->second->Relations.insert(&Rel);<br>
> + FilesToUpdate[AbsPath] = IGN.Digest;<br>
> }<br>
> <br>
> - // Build and store new slabs for each updated file.<br>
> - for (const auto &FileIt : Files) {<br>
> - llvm::StringRef Path = FileIt.getKey();<br>
> - SymbolSlab::Builder Syms;<br>
> - RefSlab::Builder Refs;<br>
> - RelationSlab::Builder Relations;<br>
> - for (const auto *S : FileIt.second.Symbols)<br>
> - Syms.insert(*S);<br>
> - for (const auto *R : FileIt.second.Refs)<br>
> - Refs.insert(RefToIDs[R], *R);<br>
> - for (const auto *Rel : FileIt.second.Relations)<br>
> - Relations.insert(*Rel);<br>
> - auto SS = std::make_unique<SymbolSlab>(std::move(Syms).build());<br>
> - auto RS = std::make_unique<RefSlab>(std::move(Refs).build());<br>
> - auto RelS =<br>
> std::make_unique<RelationSlab>(std::move(Relations).build());<br>
> - auto IG = std::make_unique<IncludeGraph>(<br>
> - getSubGraph(URI::create(Path), Index.Sources.getValue()));<br>
> + // Shard slabs into files.<br>
> + FileShardedIndex ShardedIndex(std::move(Index), MainFile);<br>
> <br>
> - // We need to store shards before updating the index, since the<br>
> latter<br>
> - // consumes slabs.<br>
> - // FIXME: Also skip serializing the shard if it is already up-<br>
> to-date.<br>
> - BackgroundIndexStorage *IndexStorage =<br>
> IndexStorageFactory(Path);<br>
> - IndexFileOut Shard;<br>
> - Shard.Symbols = SS.get();<br>
> - Shard.Refs = RS.get();<br>
> - Shard.Relations = RelS.get();<br>
> - Shard.Sources = IG.get();<br>
> + // Build and store new slabs for each updated file.<br>
> + for (const auto &FileIt : FilesToUpdate) {<br>
> + PathRef Path = FileIt.first();<br>
> + auto IF = ShardedIndex.getShard(Path);<br>
> <br>
> // Only store command line hash for main files of the TU, since<br>
> our<br>
> // current model keeps only one version of a header file.<br>
> - if (Path == MainFile)<br>
> - Shard.Cmd = Index.Cmd.getPointer();<br>
> + if (Path != MainFile)<br>
> + IF.Cmd.reset();<br>
> <br>
> - if (auto Error = IndexStorage->storeShard(Path, Shard))<br>
> + // We need to store shards before updating the index, since the<br>
> latter<br>
> + // consumes slabs.<br>
> + // FIXME: Also skip serializing the shard if it is already up-<br>
> to-date.<br>
> + if (auto Error = IndexStorageFactory(Path)->storeShard(Path,<br>
> IF))<br>
> elog("Failed to write background-index shard for file {0}:<br>
> {1}", Path,<br>
> std::move(Error));<br>
> <br>
> {<br>
> std::lock_guard<std::mutex> Lock(ShardVersionsMu);<br>
> - auto Hash = FileIt.second.Digest;<br>
> + const auto &Hash = FileIt.getValue();<br>
> auto DigestIt = ShardVersions.try_emplace(Path);<br>
> ShardVersion &SV = DigestIt.first->second;<br>
> // Skip if file is already up to date, unless previous index<br>
> was broken<br>
> @@ -333,8 +224,11 @@ void BackgroundIndex::update(<br>
> // This can override a newer version that is added in another<br>
> thread, if<br>
> // this thread sees the older version but finishes later. This<br>
> should be<br>
> // rare in practice.<br>
> - IndexedSymbols.update(Path, std::move(SS), std::move(RS),<br>
> std::move(RelS),<br>
> - Path == MainFile);<br>
> + IndexedSymbols.update(<br>
> + Path,<br>
> std::make_unique<SymbolSlab>(std::move(*IF.Symbols)),<br>
> + std::make_unique<RefSlab>(std::move(*IF.Refs)),<br>
> + std::make_unique<RelationSlab>(std::move(*IF.Relations)),<br>
> + Path == MainFile);<br>
> }<br>
> }<br>
> }<br>
> <br>
> diff --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-<br>
> tools-extra/clangd/index/FileIndex.cpp<br>
> index 92e7316105c7..d644268b8da9 100644<br>
> --- a/clang-tools-extra/clangd/index/FileIndex.cpp<br>
> +++ b/clang-tools-extra/clangd/index/FileIndex.cpp<br>
> @@ -10,11 +10,17 @@<br>
> #include "CollectMacros.h"<br>
> #include "Logger.h"<br>
> #include "ParsedAST.h"<br>
> +#include "Path.h"<br>
> #include "SymbolCollector.h"<br>
> #include "index/CanonicalIncludes.h"<br>
> #include "index/Index.h"<br>
> #include "index/MemIndex.h"<br>
> #include "index/Merge.h"<br>
> +#include "index/Ref.h"<br>
> +#include "index/Relation.h"<br>
> +#include "index/Serialization.h"<br>
> +#include "index/Symbol.h"<br>
> +#include "index/SymbolID.h"<br>
> #include "index/SymbolOrigin.h"<br>
> #include "index/dex/Dex.h"<br>
> #include "clang/AST/ASTContext.h"<br>
> @@ -23,19 +29,24 @@<br>
> #include "clang/Lex/MacroInfo.h"<br>
> #include "clang/Lex/Preprocessor.h"<br>
> #include "llvm/ADT/DenseMap.h"<br>
> -#include "llvm/ADT/DenseSet.h"<br>
> #include "llvm/ADT/STLExtras.h"<br>
> +#include "llvm/ADT/StringMap.h"<br>
> #include "llvm/ADT/StringRef.h"<br>
> +#include "llvm/Support/Error.h"<br>
> #include <memory><br>
> +#include <tuple><br>
> +#include <utility><br>
> +#include <vector><br>
> <br>
> namespace clang {<br>
> namespace clangd {<br>
> +namespace {<br>
> <br>
> -static SlabTuple indexSymbols(ASTContext &AST,<br>
> std::shared_ptr<Preprocessor> PP,<br>
> - llvm::ArrayRef<Decl *> DeclsToIndex,<br>
> - const MainFileMacros<br>
> *MacroRefsToIndex,<br>
> - const CanonicalIncludes &Includes,<br>
> - bool IsIndexMainAST, llvm::StringRef<br>
> Version) {<br>
> +SlabTuple indexSymbols(ASTContext &AST,<br>
> std::shared_ptr<Preprocessor> PP,<br>
> + llvm::ArrayRef<Decl *> DeclsToIndex,<br>
> + const MainFileMacros *MacroRefsToIndex,<br>
> + const CanonicalIncludes &Includes, bool<br>
> IsIndexMainAST,<br>
> + llvm::StringRef Version) {<br>
> SymbolCollector::Options CollectorOpts;<br>
> CollectorOpts.CollectIncludePath = true;<br>
> CollectorOpts.Includes = &Includes;<br>
> @@ -85,6 +96,131 @@ static SlabTuple indexSymbols(ASTContext &AST,<br>
> std::shared_ptr<Preprocessor> PP,<br>
> std::move(Relations));<br>
> }<br>
> <br>
> +// Resolves URI to file paths with cache.<br>
> +class URIToFileCache {<br>
> +public:<br>
> + URIToFileCache(PathRef HintPath) : HintPath(HintPath) {}<br>
> +<br>
> + llvm::StringRef operator[](llvm::StringRef FileURI) {<br>
> + if (FileURI.empty())<br>
> + return "";<br>
> + auto I = URIToPathCache.try_emplace(FileURI);<br>
> + if (I.second) {<br>
> + I.first->second = llvm::cantFail(URI::resolve(FileURI,<br>
> HintPath),<br>
> + "Failed to resolve URI");<br>
> + }<br>
> + return I.first->second;<br>
> + }<br>
> +<br>
> +private:<br>
> + PathRef HintPath;<br>
> + llvm::StringMap<std::string> URIToPathCache;<br>
> +};<br>
> +<br>
> +// We keep only the node "U" and its edges. Any node other than "U"<br>
> will be<br>
> +// empty in the resultant graph.<br>
> +IncludeGraph getSubGraph(llvm::StringRef URI, const IncludeGraph<br>
> &FullGraph) {<br>
> + IncludeGraph IG;<br>
> +<br>
> + auto Entry = IG.try_emplace(URI).first;<br>
> + auto &Node = Entry->getValue();<br>
> + Node = FullGraph.lookup(Entry->getKey());<br>
> + Node.URI = Entry->getKey();<br>
> +<br>
> + // URIs inside nodes must point into the keys of the same<br>
> IncludeGraph.<br>
> + for (auto &Include : Node.DirectIncludes) {<br>
> + auto I = IG.try_emplace(Include).first;<br>
> + I->getValue().URI = I->getKey();<br>
> + Include = I->getKey();<br>
> + }<br>
> + return IG;<br>
> +}<br>
> +} // namespace<br>
> +<br>
> +FileShardedIndex::FileShardedIndex(IndexFileIn Input, PathRef<br>
> HintPath)<br>
> + : Index(std::move(Input)) {<br>
> + URIToFileCache UriToFile(HintPath);<br>
> + // Used to build RelationSlabs.<br>
> + llvm::DenseMap<SymbolID, FileShard *> SymbolIDToFile;<br>
> +<br>
> + // Attribute each Symbol to both their declaration and definition<br>
> locations.<br>
> + if (Index.Symbols) {<br>
> + for (const auto &S : *Index.Symbols) {<br>
> + auto File = UriToFile[S.CanonicalDeclaration.FileURI];<br>
> + auto It = Shards.try_emplace(File);<br>
> + It.first->getValue().Symbols.insert(&S);<br>
> + SymbolIDToFile[<a href="http://S.ID" rel="noreferrer" target="_blank">S.ID</a>] = &It.first->getValue();<br>
> + // Only bother if definition file is <br>
> diff erent than declaration file.<br>
> + if (S.Definition &&<br>
> + S.Definition.FileURI != S.CanonicalDeclaration.FileURI) {<br>
> + auto File = UriToFile[S.Definition.FileURI];<br>
> + auto It = Shards.try_emplace(File);<br>
> + It.first->getValue().Symbols.insert(&S);<br>
> + }<br>
> + }<br>
> + }<br>
> + // Attribute references into each file they occured in.<br>
> + if (Index.Refs) {<br>
> + for (const auto &SymRefs : *Index.Refs) {<br>
> + for (const auto &R : SymRefs.second) {<br>
> + auto File = UriToFile[R.Location.FileURI];<br>
> + const auto It = Shards.try_emplace(File);<br>
> + It.first->getValue().Refs.insert(&R);<br>
> + RefToSymID[&R] = SymRefs.first;<br>
> + }<br>
> + }<br>
> + }<br>
> + // Attribute relations to the file declaraing their Subject as<br>
> Object might<br>
> + // not have been indexed, see SymbolCollector::processRelations<br>
> for details.<br>
> + if (Index.Relations) {<br>
> + for (const auto &R : *Index.Relations) {<br>
> + auto *File = SymbolIDToFile.lookup(R.Subject);<br>
> + assert(File && "unknown subject in relation");<br>
> + File->Relations.insert(&R);<br>
> + }<br>
> + }<br>
> + // Store only the direct includes of a file in a shard.<br>
> + if (Index.Sources) {<br>
> + const auto &FullGraph = *Index.Sources;<br>
> + for (const auto &It : FullGraph) {<br>
> + auto File = UriToFile[It.first()];<br>
> + auto ShardIt = Shards.try_emplace(File);<br>
> + ShardIt.first->getValue().IG = getSubGraph(It.first(),<br>
> FullGraph);<br>
> + }<br>
> + }<br>
> +}<br>
> +std::vector<PathRef> FileShardedIndex::getAllFiles() const {<br>
> + return {Shards.keys().begin(), Shards.keys().end()};<br>
> +}<br>
> +<br>
> +IndexFileIn FileShardedIndex::getShard(PathRef File) const {<br>
> + auto It = Shards.find(File);<br>
> + assert(It != Shards.end() && "received unknown file");<br>
> +<br>
> + IndexFileIn IF;<br>
> + IF.Sources = It->getValue().IG;<br>
> + IF.Cmd = Index.Cmd;<br>
> +<br>
> + SymbolSlab::Builder SymB;<br>
> + for (const auto *S : It->getValue().Symbols)<br>
> + SymB.insert(*S);<br>
> + IF.Symbols = std::move(SymB).build();<br>
> +<br>
> + RefSlab::Builder RefB;<br>
> + for (const auto *Ref : It->getValue().Refs) {<br>
> + auto SID = RefToSymID.lookup(Ref);<br>
> + RefB.insert(SID, *Ref);<br>
> + }<br>
> + IF.Refs = std::move(RefB).build();<br>
> +<br>
> + RelationSlab::Builder RelB;<br>
> + for (const auto *Rel : It->getValue().Relations) {<br>
> + RelB.insert(*Rel);<br>
> + }<br>
> + IF.Relations = std::move(RelB).build();<br>
> + return IF;<br>
> +}<br>
> +<br>
> SlabTuple indexMainDecls(ParsedAST &AST) {<br>
> return indexSymbols(AST.getASTContext(), AST.getPreprocessorPtr(),<br>
> AST.getLocalTopLevelDecls(), &AST.getMacros(),<br>
> @@ -254,15 +390,24 @@ void FileIndex::updatePreamble(PathRef Path,<br>
> llvm::StringRef Version,<br>
> ASTContext &AST,<br>
> std::shared_ptr<Preprocessor> PP,<br>
> const CanonicalIncludes &Includes) {<br>
> - auto Slabs = indexHeaderSymbols(Version, AST, std::move(PP),<br>
> Includes);<br>
> - PreambleSymbols.update(<br>
> - Path,<br>
> std::make_unique<SymbolSlab>(std::move(std::get<0>(Slabs))),<br>
> - std::make_unique<RefSlab>(),<br>
> - std::make_unique<RelationSlab>(std::move(std::get<2>(Slabs))),<br>
> - /*CountReferences=*/false);<br>
> + IndexFileIn IF;<br>
> + std::tie(IF.Symbols, std::ignore, IF.Relations) =<br>
> + indexHeaderSymbols(Version, AST, std::move(PP), Includes);<br>
> + FileShardedIndex ShardedIndex(std::move(IF), Path);<br>
> + for (PathRef File : ShardedIndex.getAllFiles()) {<br>
> + auto IF = ShardedIndex.getShard(File);<br>
> + PreambleSymbols.update(<br>
> + File, std::make_unique<SymbolSlab>(std::move(*IF.Symbols)),<br>
> + std::make_unique<RefSlab>(),<br>
> + std::make_unique<RelationSlab>(std::move(*IF.Relations)),<br>
> + /*CountReferences=*/false);<br>
> + }<br>
> PreambleIndex.reset(<br>
> PreambleSymbols.buildIndex(UseDex ? IndexType::Heavy :<br>
> IndexType::Light,<br>
> DuplicateHandling::PickOne));<br>
> + vlog("Build dynamic index for header symbols with estimated memory<br>
> usage of "<br>
> + "{0} bytes",<br>
> + PreambleIndex.estimateMemoryUsage());<br>
> }<br>
> <br>
> void FileIndex::updateMain(PathRef Path, ParsedAST &AST) {<br>
> @@ -274,6 +419,9 @@ void FileIndex::updateMain(PathRef Path,<br>
> ParsedAST &AST) {<br>
> /*CountReferences=*/true);<br>
> MainFileIndex.reset(<br>
> MainFileSymbols.buildIndex(IndexType::Light,<br>
> DuplicateHandling::Merge));<br>
> + vlog("Build dynamic index for main-file symbols with estimated<br>
> memory usage "<br>
> + "of {0} bytes",<br>
> + MainFileIndex.estimateMemoryUsage());<br>
> }<br>
> <br>
> } // namespace clangd<br>
> <br>
> diff --git a/clang-tools-extra/clangd/index/FileIndex.h b/clang-<br>
> tools-extra/clangd/index/FileIndex.h<br>
> index ec44be9b89c2..539f232a7523 100644<br>
> --- a/clang-tools-extra/clangd/index/FileIndex.h<br>
> +++ b/clang-tools-extra/clangd/index/FileIndex.h<br>
> @@ -15,14 +15,24 @@<br>
> #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_FILEINDEX_H<br>
> #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_FILEINDEX_H<br>
> <br>
> +#include "Headers.h"<br>
> #include "Index.h"<br>
> #include "MemIndex.h"<br>
> #include "Merge.h"<br>
> #include "Path.h"<br>
> #include "index/CanonicalIncludes.h"<br>
> +#include "index/Ref.h"<br>
> +#include "index/Relation.h"<br>
> +#include "index/Serialization.h"<br>
> #include "index/Symbol.h"<br>
> #include "clang/Lex/Preprocessor.h"<br>
> +#include "clang/Tooling/CompilationDatabase.h"<br>
> +#include "llvm/ADT/DenseSet.h"<br>
> +#include "llvm/ADT/Optional.h"<br>
> +#include "llvm/ADT/StringMap.h"<br>
> +#include "llvm/ADT/StringRef.h"<br>
> #include <memory><br>
> +#include <vector><br>
> <br>
> namespace clang {<br>
> class ASTContext;<br>
> @@ -109,17 +119,15 @@ class FileIndex : public MergedIndex {<br>
> private:<br>
> bool UseDex; // FIXME: this should be always on.<br>
> <br>
> - // Contains information from each file's preamble only.<br>
> - // These are large, but update fairly infrequently (preambles are<br>
> stable).<br>
> + // Contains information from each file's preamble only. Symbols<br>
> and relations<br>
> + // are sharded per declaration file to deduplicate multiple<br>
> symbols and reduce<br>
> + // memory usage.<br>
> // Missing information:<br>
> // - symbol refs (these are always "from the main file")<br>
> // - definition locations in the main file<br>
> //<br>
> - // FIXME: Because the preambles for <br>
> diff erent TUs have large overlap and<br>
> - // FileIndex doesn't deduplicate, this uses lots of extra RAM.<br>
> - // The biggest obstacle in fixing this: the obvious approach of<br>
> partitioning<br>
> - // by declaring file (rather than main file) fails if headers<br>
> provide<br>
> - // <br>
> diff erent symbols based on preprocessor state.<br>
> + // Note that we store only one version of a header, hence symbols<br>
> appearing in<br>
> + // <br>
> diff erent PP states will be missing.<br>
> FileSymbols PreambleSymbols;<br>
> SwapIndex PreambleIndex;<br>
> <br>
> @@ -146,6 +154,43 @@ SlabTuple indexHeaderSymbols(llvm::StringRef<br>
> Version, ASTContext &AST,<br>
> std::shared_ptr<Preprocessor> PP,<br>
> const CanonicalIncludes &Includes);<br>
> <br>
> +/// Takes slabs coming from a TU (multiple files) and shards them<br>
> per<br>
> +/// declaration location.<br>
> +struct FileShardedIndex {<br>
> + /// \p HintPath is used to convert file URIs stored in symbols<br>
> into absolute<br>
> + /// paths.<br>
> + explicit FileShardedIndex(IndexFileIn Input, PathRef HintPath);<br>
> +<br>
> + /// Returns absolute paths for all files that has a shard.<br>
> + std::vector<PathRef> getAllFiles() const;<br>
> +<br>
> + /// Generates index shard for the \p File. Note that this function<br>
> results in<br>
> + /// a copy of all the relevant data.<br>
> + /// Returned index will always have Symbol/Refs/Relation Slabs<br>
> set, even if<br>
> + /// they are empty.<br>
> + IndexFileIn getShard(PathRef File) const;<br>
> +<br>
> +private:<br>
> + // Contains all the information that belongs to a single file.<br>
> + struct FileShard {<br>
> + // Either declared or defined in the file.<br>
> + llvm::DenseSet<const Symbol *> Symbols;<br>
> + // Reference occurs in the file.<br>
> + llvm::DenseSet<const Ref *> Refs;<br>
> + // Subject is declared in the file.<br>
> + llvm::DenseSet<const Relation *> Relations;<br>
> + // Contains edges for only the direct includes.<br>
> + IncludeGraph IG;<br>
> + };<br>
> +<br>
> + // Keeps all the information alive.<br>
> + const IndexFileIn Index;<br>
> + // Mapping from absolute paths to slab information.<br>
> + llvm::StringMap<FileShard> Shards;<br>
> + // Used to build RefSlabs.<br>
> + llvm::DenseMap<const Ref *, SymbolID> RefToSymID;<br>
> +};<br>
> +<br>
> } // namespace clangd<br>
> } // namespace clang<br>
> <br>
> <br>
> diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp<br>
> b/clang-tools-extra/clangd/index/SymbolCollector.cpp<br>
> index 06190914ee8d..471061672107 100644<br>
> --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp<br>
> +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp<br>
> @@ -283,6 +283,18 @@ bool SymbolCollector::handleDeclOccurrence(<br>
> if (!ID)<br>
> return true;<br>
> <br>
> + // ND is the canonical (i.e. first) declaration. If it's in the<br>
> main file<br>
> + // (which is not a header), then no public declaration was<br>
> visible, so assume<br>
> + // it's main-file only.<br>
> + bool IsMainFileOnly =<br>
> + SM.isWrittenInMainFile(SM.getExpansionLoc(ND->getBeginLoc()))<br>
> &&<br>
> + !isHeaderFile(SM.getFileEntryForID(SM.getMainFileID())-<br>
> >getName(),<br>
> + ASTCtx->getLangOpts());<br>
> + // In C, printf is a redecl of an implicit builtin! So check OrigD<br>
> instead.<br>
> + if (ASTNode.OrigD->isImplicit() ||<br>
> + !shouldCollectSymbol(*ND, *ASTCtx, Opts, IsMainFileOnly))<br>
> + return true;<br>
> +<br>
> // Note: we need to process relations for all decl occurrences,<br>
> including<br>
> // refs, because the indexing code only populates relations for<br>
> specific<br>
> // occurrences. For example, RelationBaseOf is only populated for<br>
> the<br>
> @@ -297,17 +309,6 @@ bool SymbolCollector::handleDeclOccurrence(<br>
> if (IsOnlyRef && !CollectRef)<br>
> return true;<br>
> <br>
> - // ND is the canonical (i.e. first) declaration. If it's in the<br>
> main file<br>
> - // (which is not a header), then no public declaration was<br>
> visible, so assume<br>
> - // it's main-file only.<br>
> - bool IsMainFileOnly =<br>
> - SM.isWrittenInMainFile(SM.getExpansionLoc(ND->getBeginLoc()))<br>
> &&<br>
> - !isHeaderFile(SM.getFileEntryForID(SM.getMainFileID())-<br>
> >getName(),<br>
> - ASTCtx->getLangOpts());<br>
> - // In C, printf is a redecl of an implicit builtin! So check OrigD<br>
> instead.<br>
> - if (ASTNode.OrigD->isImplicit() ||<br>
> - !shouldCollectSymbol(*ND, *ASTCtx, Opts, IsMainFileOnly))<br>
> - return true;<br>
> // Do not store references to main-file symbols.<br>
> // Unlike other fields, e.g. Symbols (which use spelling<br>
> locations), we use<br>
> // file locations for references (as it aligns the behavior of<br>
> clangd's<br>
> <br>
> diff --git a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp<br>
> b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp<br>
> index 5203fb67307c..dc39ad2acf25 100644<br>
> --- a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp<br>
> +++ b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp<br>
> @@ -9,13 +9,19 @@<br>
> #include "AST.h"<br>
> #include "Annotations.h"<br>
> #include "Compiler.h"<br>
> +#include "Headers.h"<br>
> #include "ParsedAST.h"<br>
> #include "SyncAPI.h"<br>
> #include "TestFS.h"<br>
> #include "TestTU.h"<br>
> +#include "URI.h"<br>
> #include "index/CanonicalIncludes.h"<br>
> #include "index/FileIndex.h"<br>
> #include "index/Index.h"<br>
> +#include "index/Ref.h"<br>
> +#include "index/Relation.h"<br>
> +#include "index/Serialization.h"<br>
> +#include "index/Symbol.h"<br>
> #include "clang/Frontend/CompilerInvocation.h"<br>
> #include "clang/Frontend/Utils.h"<br>
> #include "clang/Index/IndexSymbol.h"<br>
> @@ -23,6 +29,7 @@<br>
> #include "clang/Tooling/CompilationDatabase.h"<br>
> #include "gmock/gmock.h"<br>
> #include "gtest/gtest.h"<br>
> +#include <utility><br>
> <br>
> using ::testing::_;<br>
> using ::testing::AllOf;<br>
> @@ -151,8 +158,9 @@ void update(FileIndex &M, llvm::StringRef<br>
> Basename, llvm::StringRef Code) {<br>
> File.HeaderFilename = (Basename + ".h").str();<br>
> File.HeaderCode = std::string(Code);<br>
> auto AST = File.build();<br>
> - M.updatePreamble(File.Filename, /*Version=*/"null",<br>
> AST.getASTContext(),<br>
> - AST.getPreprocessorPtr(),<br>
> AST.getCanonicalIncludes());<br>
> + M.updatePreamble(testPath(File.Filename), /*Version=*/"null",<br>
> + AST.getASTContext(), AST.getPreprocessorPtr(),<br>
> + AST.getCanonicalIncludes());<br>
> }<br>
> <br>
> TEST(FileIndexTest, CustomizedURIScheme) {<br>
> @@ -393,8 +401,9 @@ TEST(FileIndexTest, Relations) {<br>
> TU.HeaderCode = "class A {}; class B : public A {};";<br>
> auto AST = TU.build();<br>
> FileIndex Index;<br>
> - Index.updatePreamble(TU.Filename, /*Version=*/"null",<br>
> AST.getASTContext(),<br>
> - AST.getPreprocessorPtr(),<br>
> AST.getCanonicalIncludes());<br>
> + Index.updatePreamble(testPath(TU.Filename), /*Version=*/"null",<br>
> + AST.getASTContext(),<br>
> AST.getPreprocessorPtr(),<br>
> + AST.getCanonicalIncludes());<br>
> SymbolID A = findSymbol(TU.headerSymbols(), "A").ID;<br>
> uint32_t Results = 0;<br>
> RelationsRequest Req;<br>
> @@ -477,6 +486,128 @@ TEST(FileSymbolsTest,<br>
> CountReferencesWithRefSlabs) {<br>
> AllOf(QName("2"), NumReferences(1u)),<br>
> AllOf(QName("3"), NumReferences(1u))));<br>
> }<br>
> +<br>
> +TEST(FileIndexTest, StalePreambleSymbolsDeleted) {<br>
> + FileIndex M;<br>
> + TestTU File;<br>
> + File.HeaderFilename = "a.h";<br>
> +<br>
> + File.Filename = "f1.cpp";<br>
> + File.HeaderCode = "int a;";<br>
> + auto AST = File.build();<br>
> + M.updatePreamble(testPath(File.Filename), /*Version=*/"null",<br>
> + AST.getASTContext(), AST.getPreprocessorPtr(),<br>
> + AST.getCanonicalIncludes());<br>
> + EXPECT_THAT(runFuzzyFind(M, ""),<br>
> UnorderedElementsAre(QName("a")));<br>
> +<br>
> + File.Filename = "f2.cpp";<br>
> + File.HeaderCode = "int b;";<br>
> + AST = File.build();<br>
> + M.updatePreamble(testPath(File.Filename), /*Version=*/"null",<br>
> + AST.getASTContext(), AST.getPreprocessorPtr(),<br>
> + AST.getCanonicalIncludes());<br>
> + EXPECT_THAT(runFuzzyFind(M, ""),<br>
> UnorderedElementsAre(QName("b")));<br>
> +}<br>
> +<br>
> +TEST(FileShardedIndexTest, Sharding) {<br>
> + auto AHeaderUri = URI::create(testPath("a.h")).toString();<br>
> + auto BHeaderUri = URI::create(testPath("b.h")).toString();<br>
> + auto BSourceUri = URI::create(testPath("b.cc")).toString();<br>
> +<br>
> + auto Sym1 = symbol("1");<br>
> + Sym1.CanonicalDeclaration.FileURI = AHeaderUri.c_str();<br>
> +<br>
> + auto Sym2 = symbol("2");<br>
> + Sym2.CanonicalDeclaration.FileURI = BHeaderUri.c_str();<br>
> + Sym2.Definition.FileURI = BSourceUri.c_str();<br>
> +<br>
> + IndexFileIn IF;<br>
> + {<br>
> + SymbolSlab::Builder B;<br>
> + // Should be stored in only a.h<br>
> + B.insert(Sym1);<br>
> + // Should be stored in both b.h and b.cc<br>
> + B.insert(Sym2);<br>
> + IF.Symbols = std::move(B).build();<br>
> + }<br>
> + {<br>
> + // Should be stored in b.cc<br>
> + IF.Refs = std::move(*refSlab(Sym1.ID,<br>
> BSourceUri.c_str()).release());<br>
> + }<br>
> + {<br>
> + RelationSlab::Builder B;<br>
> + // Should be stored in a.h<br>
> + B.insert(Relation{Sym1.ID, RelationKind::BaseOf, Sym2.ID});<br>
> + // Should be stored in b.h<br>
> + B.insert(Relation{Sym2.ID, RelationKind::BaseOf, Sym1.ID});<br>
> + IF.Relations = std::move(B).build();<br>
> + }<br>
> +<br>
> + IF.Sources.emplace();<br>
> + IncludeGraph &IG = *IF.Sources;<br>
> + {<br>
> + // b.cc includes b.h<br>
> + auto &Node = IG[BSourceUri];<br>
> + Node.DirectIncludes = {BHeaderUri};<br>
> + Node.URI = BSourceUri;<br>
> + }<br>
> + {<br>
> + // b.h includes a.h<br>
> + auto &Node = IG[BHeaderUri];<br>
> + Node.DirectIncludes = {AHeaderUri};<br>
> + Node.URI = BHeaderUri;<br>
> + }<br>
> + {<br>
> + // a.h includes nothing.<br>
> + auto &Node = IG[AHeaderUri];<br>
> + Node.DirectIncludes = {};<br>
> + Node.URI = AHeaderUri;<br>
> + }<br>
> +<br>
> + IF.Cmd = tooling::CompileCommand(testRoot(), "b.cc", {"clang"},<br>
> "out");<br>
> +<br>
> + FileShardedIndex ShardedIndex(std::move(IF), testPath("b.cc"));<br>
> + ASSERT_THAT(<br>
> + ShardedIndex.getAllFiles(),<br>
> + UnorderedElementsAre(testPath("a.h"), testPath("b.h"),<br>
> testPath("b.cc")));<br>
> +<br>
> + {<br>
> + auto Shard = ShardedIndex.getShard(testPath("a.h"));<br>
> + EXPECT_THAT(Shard.Symbols.getValue(),<br>
> UnorderedElementsAre(QName("1")));<br>
> + EXPECT_THAT(Shard.Refs.getValue(), IsEmpty());<br>
> + EXPECT_THAT(<br>
> + Shard.Relations.getValue(),<br>
> + UnorderedElementsAre(Relation{Sym1.ID, RelationKind::BaseOf,<br>
> Sym2.ID}));<br>
> + ASSERT_THAT(Shard.Sources.getValue().keys(),<br>
> + UnorderedElementsAre(AHeaderUri));<br>
> + EXPECT_THAT(Shard.Sources->lookup(AHeaderUri).DirectIncludes,<br>
> IsEmpty());<br>
> + EXPECT_TRUE(Shard.Cmd.hasValue());<br>
> + }<br>
> + {<br>
> + auto Shard = ShardedIndex.getShard(testPath("b.h"));<br>
> + EXPECT_THAT(Shard.Symbols.getValue(),<br>
> UnorderedElementsAre(QName("2")));<br>
> + EXPECT_THAT(Shard.Refs.getValue(), IsEmpty());<br>
> + EXPECT_THAT(<br>
> + Shard.Relations.getValue(),<br>
> + UnorderedElementsAre(Relation{Sym2.ID, RelationKind::BaseOf,<br>
> Sym1.ID}));<br>
> + ASSERT_THAT(Shard.Sources.getValue().keys(),<br>
> + UnorderedElementsAre(BHeaderUri, AHeaderUri));<br>
> + EXPECT_THAT(Shard.Sources->lookup(BHeaderUri).DirectIncludes,<br>
> + UnorderedElementsAre(AHeaderUri));<br>
> + EXPECT_TRUE(Shard.Cmd.hasValue());<br>
> + }<br>
> + {<br>
> + auto Shard = ShardedIndex.getShard(testPath("b.cc"));<br>
> + EXPECT_THAT(Shard.Symbols.getValue(),<br>
> UnorderedElementsAre(QName("2")));<br>
> + EXPECT_THAT(Shard.Refs.getValue(),<br>
> UnorderedElementsAre(Pair(Sym1.ID, _)));<br>
> + EXPECT_THAT(Shard.Relations.getValue(), IsEmpty());<br>
> + ASSERT_THAT(Shard.Sources.getValue().keys(),<br>
> + UnorderedElementsAre(BSourceUri, BHeaderUri));<br>
> + EXPECT_THAT(Shard.Sources->lookup(BSourceUri).DirectIncludes,<br>
> + UnorderedElementsAre(BHeaderUri));<br>
> + EXPECT_TRUE(Shard.Cmd.hasValue());<br>
> + }<br>
> +}<br>
> } // namespace<br>
> } // namespace clangd<br>
> } // namespace clang<br>
> <br>
> diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-<br>
> tools-extra/clangd/unittests/TestTU.cpp<br>
> index fe3e8f01cca8..640d067261bd 100644<br>
> --- a/clang-tools-extra/clangd/unittests/TestTU.cpp<br>
> +++ b/clang-tools-extra/clangd/unittests/TestTU.cpp<br>
> @@ -116,9 +116,10 @@ SymbolSlab TestTU::headerSymbols() const {<br>
> std::unique_ptr<SymbolIndex> TestTU::index() const {<br>
> auto AST = build();<br>
> auto Idx = std::make_unique<FileIndex>(/*UseDex=*/true);<br>
> - Idx->updatePreamble(Filename, /*Version=*/"null",<br>
> AST.getASTContext(),<br>
> - AST.getPreprocessorPtr(),<br>
> AST.getCanonicalIncludes());<br>
> - Idx->updateMain(Filename, AST);<br>
> + Idx->updatePreamble(testPath(Filename), /*Version=*/"null",<br>
> + AST.getASTContext(), AST.getPreprocessorPtr(),<br>
> + AST.getCanonicalIncludes());<br>
> + Idx->updateMain(testPath(Filename), AST);<br>
> return std::move(Idx);<br>
> }<br>
> <br>
> <br>
> <br>
> <br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>