Hi Kadir, It seems this commit started causing failures on builds in green dragon, starting from: http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/52811/ <http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/52811/>
Can you please take a look, and revert if the fix isn’t straight forward. Thanks, Amara > On Jan 10, 2019, at 9:03 AM, Kadir Cetinkaya via cfe-commits > <cfe-commits@lists.llvm.org> wrote: > > Author: kadircet > Date: Thu Jan 10 09:03:04 2019 > New Revision: 350847 > > URL: http://llvm.org/viewvc/llvm-project?rev=350847&view=rev > Log: > [clangd] Introduce loading of shards within auto-index > > Summary: > Whenever a change happens on a CDB, load shards associated with that > CDB before issuing re-index actions. > > Reviewers: ilya-biryukov > > Reviewed By: ilya-biryukov > > Subscribers: ioeric, MaskRay, jkorous, arphaman, cfe-commits > > Differential Revision: https://reviews.llvm.org/D55224 > > Modified: > clang-tools-extra/trunk/clangd/index/Background.cpp > clang-tools-extra/trunk/clangd/index/Background.h > clang-tools-extra/trunk/test/clangd/background-index.test > clang-tools-extra/trunk/unittests/clangd/BackgroundIndexTests.cpp > > Modified: clang-tools-extra/trunk/clangd/index/Background.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/index/Background.cpp?rev=350847&r1=350846&r2=350847&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/index/Background.cpp (original) > +++ clang-tools-extra/trunk/clangd/index/Background.cpp Thu Jan 10 09:03:04 > 2019 > @@ -115,6 +115,19 @@ createFileFilter(const llvm::StringMap<F > }; > } > > +// We cannot use vfs->makeAbsolute because Cmd.FileName is either absolute or > +// relative to Cmd.Directory, which might not be the same as current working > +// directory. > +llvm::SmallString<128> getAbsolutePath(const tooling::CompileCommand &Cmd) { > + llvm::SmallString<128> AbsolutePath; > + if (llvm::sys::path::is_absolute(Cmd.Filename)) { > + AbsolutePath = Cmd.Filename; > + } else { > + AbsolutePath = Cmd.Directory; > + llvm::sys::path::append(AbsolutePath, Cmd.Filename); > + } > + return AbsolutePath; > +} > } // namespace > > BackgroundIndex::BackgroundIndex( > @@ -204,40 +217,33 @@ void BackgroundIndex::enqueue(const std: > [this, ChangedFiles] { > trace::Span Tracer("BackgroundIndexEnqueue"); > // We're doing this asynchronously, because we'll read shards here > too. > - // FIXME: read shards here too. > - > log("Enqueueing {0} commands for indexing", ChangedFiles.size()); > SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size())); > > - // We shuffle the files because processing them in a random order > should > - // quickly give us good coverage of headers in the project. > - std::vector<unsigned> Permutation(ChangedFiles.size()); > - std::iota(Permutation.begin(), Permutation.end(), 0); > - std::mt19937 Generator(std::random_device{}()); > - std::shuffle(Permutation.begin(), Permutation.end(), Generator); > - > - for (const unsigned I : Permutation) > - enqueue(ChangedFiles[I]); > + auto NeedsReIndexing = loadShards(std::move(ChangedFiles)); > + // Run indexing for files that need to be updated. > + std::shuffle(NeedsReIndexing.begin(), NeedsReIndexing.end(), > + std::mt19937(std::random_device{}())); > + for (auto &Elem : NeedsReIndexing) > + enqueue(std::move(Elem.first), Elem.second); > }, > ThreadPriority::Normal); > } > > -void BackgroundIndex::enqueue(const std::string &File) { > - ProjectInfo Project; > - if (auto Cmd = CDB.getCompileCommand(File, &Project)) { > - auto *Storage = IndexStorageFactory(Project.SourceRoot); > - // Set priority to low, since background indexing is a long running > - // task we do not want to eat up cpu when there are any other high > - // priority threads. > - enqueueTask(Bind( > - [this, File, Storage](tooling::CompileCommand Cmd) { > - Cmd.CommandLine.push_back("-resource-dir=" + > ResourceDir); > - if (auto Error = index(std::move(Cmd), Storage)) > - log("Indexing {0} failed: {1}", File, > std::move(Error)); > - }, > - std::move(*Cmd)), > - ThreadPriority::Low); > - } > +void BackgroundIndex::enqueue(tooling::CompileCommand Cmd, > + BackgroundIndexStorage *Storage) { > + enqueueTask(Bind( > + [this, Storage](tooling::CompileCommand Cmd) { > + Cmd.CommandLine.push_back("-resource-dir=" + > ResourceDir); > + // We can't use llvm::StringRef here since we are going > to > + // move from Cmd during the call below. > + const std::string FileName = Cmd.Filename; > + if (auto Error = index(std::move(Cmd), Storage)) > + elog("Indexing {0} failed: {1}", FileName, > + std::move(Error)); > + }, > + std::move(Cmd)), > + ThreadPriority::Low); > } > > void BackgroundIndex::enqueueTask(Task T, ThreadPriority Priority) { > @@ -299,22 +305,22 @@ void BackgroundIndex::update(llvm::Strin > } > > // Build and store new slabs for each updated file. > - for (const auto &F : Files) { > - llvm::StringRef Path = F.first(); > - vlog("Update symbols in {0}", Path); > + for (const auto &I : *Index.Sources) { > + std::string Path = URICache.resolve(I.first()); > SymbolSlab::Builder Syms; > RefSlab::Builder Refs; > - for (const auto *S : F.second.Symbols) > - Syms.insert(*S); > - for (const auto *R : F.second.Refs) > - Refs.insert(RefToIDs[R], *R); > - > + auto FileIt = Files.find(Path); > + if (FileIt != Files.end()) { > + auto &F = *FileIt; > + for (const auto *S : F.second.Symbols) > + Syms.insert(*S); > + for (const auto *R : F.second.Refs) > + Refs.insert(RefToIDs[R], *R); > + } > auto SS = llvm::make_unique<SymbolSlab>(std::move(Syms).build()); > auto RS = llvm::make_unique<RefSlab>(std::move(Refs).build()); > auto IG = llvm::make_unique<IncludeGraph>( > getSubGraph(URI::create(Path), Index.Sources.getValue())); > - > - auto Hash = FilesToUpdate.lookup(Path); > // We need to store shards before updating the index, since the latter > // consumes slabs. > if (IndexStorage) { > @@ -327,13 +333,19 @@ void BackgroundIndex::update(llvm::Strin > elog("Failed to write background-index shard for file {0}: {1}", Path, > std::move(Error)); > } > - > - std::lock_guard<std::mutex> Lock(DigestsMu); > - // This can override a newer version that is added in another thread, > - // if this thread sees the older version but finishes later. This should > be > - // rare in practice. > - IndexedFileDigests[Path] = Hash; > - IndexedSymbols.update(Path, std::move(SS), std::move(RS)); > + { > + std::lock_guard<std::mutex> Lock(DigestsMu); > + auto Hash = I.second.Digest; > + // Skip if file is already up to date. > + auto DigestIt = IndexedFileDigests.try_emplace(Path); > + if (!DigestIt.second && DigestIt.first->second == Hash) > + continue; > + DigestIt.first->second = Hash; > + // This can override a newer version that is added in another thread, > if > + // this thread sees the older version but finishes later. This should > be > + // rare in practice. > + IndexedSymbols.update(Path, std::move(SS), std::move(RS)); > + } > } > } > > @@ -342,11 +354,11 @@ void BackgroundIndex::buildIndex() { > while (true) { > { > std::unique_lock<std::mutex> Lock(IndexMu); > - if (ShouldStop) // Avoid waiting if stopped. > + if (ShouldStop) // Avoid waiting if stopped. > break; > // Wait until this is notified to stop or `BuildIndexPeriodMs` has past. > IndexCV.wait_for(Lock, std::chrono::milliseconds(BuildIndexPeriodMs)); > - if (ShouldStop) // Avoid rebuilding index if stopped. > + if (ShouldStop) // Avoid rebuilding index if stopped. > break; > } > if (!SymbolsUpdatedSinceLastIndex.exchange(false)) > @@ -365,13 +377,7 @@ llvm::Error BackgroundIndex::index(tooli > BackgroundIndexStorage *IndexStorage) { > trace::Span Tracer("BackgroundIndex"); > SPAN_ATTACH(Tracer, "file", Cmd.Filename); > - llvm::SmallString<128> AbsolutePath; > - if (llvm::sys::path::is_absolute(Cmd.Filename)) { > - AbsolutePath = Cmd.Filename; > - } else { > - AbsolutePath = Cmd.Directory; > - llvm::sys::path::append(AbsolutePath, Cmd.Filename); > - } > + auto AbsolutePath = getAbsolutePath(Cmd); > > auto FS = FSProvider.getFileSystem(); > auto Buf = FS->getBufferForFile(AbsolutePath); > @@ -383,11 +389,6 @@ llvm::Error BackgroundIndex::index(tooli > llvm::StringMap<FileDigest> DigestsSnapshot; > { > std::lock_guard<std::mutex> Lock(DigestsMu); > - if (IndexedFileDigests.lookup(AbsolutePath) == Hash) { > - vlog("No need to index {0}, already up to date", AbsolutePath); > - return llvm::Error::success(); > - } > - > DigestsSnapshot = IndexedFileDigests; > } > > @@ -437,8 +438,8 @@ llvm::Error BackgroundIndex::index(tooli > "IndexingAction failed: has uncompilable errors"); > } > > - assert(Index.Symbols && Index.Refs && Index.Sources > - && "Symbols, Refs and Sources must be set."); > + assert(Index.Symbols && Index.Refs && Index.Sources && > + "Symbols, Refs and Sources must be set."); > > log("Indexed {0} ({1} symbols, {2} refs, {3} files)", > Inputs.CompileCommand.Filename, Index.Symbols->size(), > @@ -448,12 +449,6 @@ llvm::Error BackgroundIndex::index(tooli > SPAN_ATTACH(Tracer, "sources", int(Index.Sources->size())); > > update(AbsolutePath, std::move(Index), FilesToUpdate, IndexStorage); > - { > - // Make sure hash for the main file is always updated even if there is no > - // index data in it. > - std::lock_guard<std::mutex> Lock(DigestsMu); > - IndexedFileDigests[AbsolutePath] = Hash; > - } > > if (BuildIndexPeriodMs > 0) > SymbolsUpdatedSinceLastIndex = true; > @@ -464,5 +459,146 @@ llvm::Error BackgroundIndex::index(tooli > return llvm::Error::success(); > } > > +std::vector<BackgroundIndex::Source> > +BackgroundIndex::loadShard(const tooling::CompileCommand &Cmd, > + BackgroundIndexStorage *IndexStorage, > + llvm::StringSet<> &LoadedShards) { > + struct ShardInfo { > + std::string AbsolutePath; > + std::unique_ptr<IndexFileIn> Shard; > + FileDigest Digest; > + }; > + std::vector<ShardInfo> IntermediateSymbols; > + // Make sure we don't have duplicate elements in the queue. Keys are > absolute > + // paths. > + llvm::StringSet<> InQueue; > + auto FS = FSProvider.getFileSystem(); > + // Dependencies of this TU, paired with the information about whether they > + // need to be re-indexed or not. > + std::vector<Source> Dependencies; > + std::string AbsolutePath = getAbsolutePath(Cmd).str(); > + // Up until we load the shard related to a dependency it needs to be > + // re-indexed. > + Dependencies.emplace_back(AbsolutePath, true); > + InQueue.insert(AbsolutePath); > + // Goes over each dependency. > + for (size_t CurrentDependency = 0; CurrentDependency < Dependencies.size(); > + CurrentDependency++) { > + llvm::StringRef CurDependencyPath = Dependencies[CurrentDependency].Path; > + // If we have already seen this shard before(either loaded or failed) > don't > + // re-try again. Since the information in the shard won't change from > one TU > + // to another. > + if (!LoadedShards.try_emplace(CurDependencyPath).second) { > + // If the dependency needs to be re-indexed, first occurence would > already > + // have detected that, so we don't need to issue it again. > + Dependencies[CurrentDependency].NeedsReIndexing = false; > + continue; > + } > + > + auto Shard = IndexStorage->loadShard(CurDependencyPath); > + if (!Shard || !Shard->Sources) { > + // File will be returned as requiring re-indexing to caller. > + vlog("Failed to load shard: {0}", CurDependencyPath); > + continue; > + } > + // These are the edges in the include graph for current dependency. > + for (const auto &I : *Shard->Sources) { > + auto U = URI::parse(I.getKey()); > + if (!U) > + continue; > + auto AbsolutePath = URI::resolve(*U, CurDependencyPath); > + if (!AbsolutePath) > + continue; > + // Add file as dependency if haven't seen before. > + if (InQueue.try_emplace(*AbsolutePath).second) > + Dependencies.emplace_back(*AbsolutePath, true); > + // The node contains symbol information only for current file, the > rest is > + // just edges. > + if (*AbsolutePath != CurDependencyPath) > + continue; > + > + // We found source file info for current dependency. > + assert(I.getValue().Digest != FileDigest{{0}} && "Digest is empty?"); > + ShardInfo SI; > + SI.AbsolutePath = CurDependencyPath; > + SI.Shard = std::move(Shard); > + SI.Digest = I.getValue().Digest; > + IntermediateSymbols.push_back(std::move(SI)); > + // Check if the source needs re-indexing. > + // Get the digest, skip it if file doesn't exist. > + auto Buf = FS->getBufferForFile(CurDependencyPath); > + if (!Buf) { > + elog("Couldn't get buffer for file: {0}: {1}", CurDependencyPath, > + Buf.getError().message()); > + continue; > + } > + // If digests match then dependency doesn't need re-indexing. > + Dependencies[CurrentDependency].NeedsReIndexing = > + digest(Buf->get()->getBuffer()) != I.getValue().Digest; > + } > + } > + // Load shard information into background-index. > + { > + std::lock_guard<std::mutex> Lock(DigestsMu); > + // This can override a newer version that is added in another thread, > + // if this thread sees the older version but finishes later. This > + // should be rare in practice. > + for (const ShardInfo &SI : IntermediateSymbols) { > + auto SS = > + SI.Shard->Symbols > + ? llvm::make_unique<SymbolSlab>(std::move(*SI.Shard->Symbols)) > + : nullptr; > + auto RS = SI.Shard->Refs > + ? llvm::make_unique<RefSlab>(std::move(*SI.Shard->Refs)) > + : nullptr; > + IndexedFileDigests[SI.AbsolutePath] = SI.Digest; > + IndexedSymbols.update(SI.AbsolutePath, std::move(SS), std::move(RS)); > + } > + } > + > + return Dependencies; > +} > + > +// Goes over each changed file and loads them from index. Returns the list of > +// TUs that had out-of-date/no shards. > +std::vector<std::pair<tooling::CompileCommand, BackgroundIndexStorage *>> > +BackgroundIndex::loadShards(std::vector<std::string> ChangedFiles) { > + std::vector<std::pair<tooling::CompileCommand, BackgroundIndexStorage *>> > + NeedsReIndexing; > + // Keeps track of the files that will be reindexed, to make sure we won't > + // re-index same dependencies more than once. Keys are AbsolutePaths. > + llvm::StringSet<> FilesToIndex; > + // Keeps track of the loaded shards to make sure we don't perform redundant > + // disk IO. Keys are absolute paths. > + llvm::StringSet<> LoadedShards; > + for (const auto &File : ChangedFiles) { > + ProjectInfo PI; > + auto Cmd = CDB.getCompileCommand(File, &PI); > + if (!Cmd) > + continue; > + BackgroundIndexStorage *IndexStorage = > IndexStorageFactory(PI.SourceRoot); > + auto Dependencies = loadShard(*Cmd, IndexStorage, LoadedShards); > + for (const auto &Dependency : Dependencies) { > + if (!Dependency.NeedsReIndexing || FilesToIndex.count(Dependency.Path)) > + continue; > + // FIXME: Currently, we simply schedule indexing on a TU whenever any > of > + // its dependencies needs re-indexing. We might do it smarter by > figuring > + // out a minimal set of TUs that will cover all the stale dependencies. > + vlog("Enqueueing TU {0} because its dependency {1} needs re-indexing.", > + Cmd->Filename, Dependency.Path); > + NeedsReIndexing.push_back({std::move(*Cmd), IndexStorage}); > + // Mark all of this TU's dependencies as to-be-indexed so that we won't > + // try to re-index those. > + for (const auto &Dependency : Dependencies) > + FilesToIndex.insert(Dependency.Path); > + break; > + } > + } > + vlog("Loaded all shards"); > + reset(IndexedSymbols.buildIndex(IndexType::Light, > DuplicateHandling::Merge)); > + > + return NeedsReIndexing; > +} > + > } // namespace clangd > } // namespace clang > > Modified: clang-tools-extra/trunk/clangd/index/Background.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/index/Background.h?rev=350847&r1=350846&r2=350847&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/index/Background.h (original) > +++ clang-tools-extra/trunk/clangd/index/Background.h Thu Jan 10 09:03:04 2019 > @@ -81,7 +81,6 @@ public: > // The indexing happens in a background thread, so the symbols will be > // available sometime later. > void enqueue(const std::vector<std::string> &ChangedFiles); > - void enqueue(const std::string &File); > > // Cause background threads to stop after ther current task, any remaining > // tasks will be discarded. > @@ -118,6 +117,21 @@ private: > std::mutex DigestsMu; > > BackgroundIndexStorage::Factory IndexStorageFactory; > + struct Source { > + std::string Path; > + bool NeedsReIndexing; > + Source(llvm::StringRef Path, bool NeedsReIndexing) > + : Path(Path), NeedsReIndexing(NeedsReIndexing) {} > + }; > + // Loads the shards for a single TU and all of its dependencies. Returns > the > + // list of sources and whether they need to be re-indexed. > + std::vector<Source> loadShard(const tooling::CompileCommand &Cmd, > + BackgroundIndexStorage *IndexStorage, > + llvm::StringSet<> &LoadedShards); > + // Tries to load shards for the ChangedFiles. > + std::vector<std::pair<tooling::CompileCommand, BackgroundIndexStorage *>> > + loadShards(std::vector<std::string> ChangedFiles); > + void enqueue(tooling::CompileCommand Cmd, BackgroundIndexStorage *Storage); > > // queue management > using Task = std::function<void()>; > > Modified: clang-tools-extra/trunk/test/clangd/background-index.test > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/background-index.test?rev=350847&r1=350846&r2=350847&view=diff > ============================================================================== > --- clang-tools-extra/trunk/test/clangd/background-index.test (original) > +++ clang-tools-extra/trunk/test/clangd/background-index.test Thu Jan 10 > 09:03:04 2019 > @@ -16,6 +16,5 @@ > # RUN: ls %t/.clangd-index/foo.cpp.*.idx > > # Test the index is read from disk: delete code and restart clangd. > -# FIXME: This test currently fails as we don't read the index yet. > # RUN: rm %t/foo.cpp > -# RUN: clangd -background-index -lit-test < %t/definition.jsonrpc | not > FileCheck %t/definition.jsonrpc > +# RUN: clangd -background-index -lit-test < %t/definition.jsonrpc | > FileCheck %t/definition.jsonrpc > > Modified: clang-tools-extra/trunk/unittests/clangd/BackgroundIndexTests.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/BackgroundIndexTests.cpp?rev=350847&r1=350846&r2=350847&view=diff > ============================================================================== > --- clang-tools-extra/trunk/unittests/clangd/BackgroundIndexTests.cpp > (original) > +++ clang-tools-extra/trunk/unittests/clangd/BackgroundIndexTests.cpp Thu Jan > 10 09:03:04 2019 > @@ -9,6 +9,7 @@ > > using testing::_; > using testing::AllOf; > +using testing::Contains; > using testing::ElementsAre; > using testing::Not; > using testing::UnorderedElementsAre; > @@ -146,7 +147,7 @@ TEST_F(BackgroundIndexTest, IndexTwoFile > FileURI("unittest:///root/B.cc")})); > } > > -TEST_F(BackgroundIndexTest, ShardStorageWriteTest) { > +TEST_F(BackgroundIndexTest, ShardStorageTest) { > MockFSProvider FS; > FS.Files[testPath("root/A.h")] = R"cpp( > void common(); > @@ -175,6 +176,16 @@ TEST_F(BackgroundIndexTest, ShardStorage > EXPECT_EQ(CacheHits, 0U); > EXPECT_EQ(Storage.size(), 2U); > > + { > + OverlayCDB CDB(/*Base=*/nullptr); > + BackgroundIndex Idx(Context::empty(), "", FS, CDB, > + [&](llvm::StringRef) { return &MSS; }); > + CDB.setCompileCommand(testPath("root"), Cmd); > + ASSERT_TRUE(Idx.blockUntilIdleForTest()); > + } > + EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache. > + EXPECT_EQ(Storage.size(), 2U); > + > auto ShardHeader = MSS.loadShard(testPath("root/A.h")); > EXPECT_NE(ShardHeader, nullptr); > EXPECT_THAT( > @@ -278,5 +289,73 @@ TEST_F(BackgroundIndexTest, DISABLED_Per > EXPECT_THAT(runFuzzyFind(Idx, ""), ElementsAre(Named("Y"))); > } > > +TEST_F(BackgroundIndexTest, ShardStorageLoad) { > + MockFSProvider FS; > + FS.Files[testPath("root/A.h")] = R"cpp( > + void common(); > + void f_b(); > + class A_CC {}; > + )cpp"; > + FS.Files[testPath("root/A.cc")] = > + "#include \"A.h\"\nvoid g() { (void)common; }"; > + > + llvm::StringMap<std::string> Storage; > + size_t CacheHits = 0; > + MemoryShardStorage MSS(Storage, CacheHits); > + > + tooling::CompileCommand Cmd; > + Cmd.Filename = testPath("root/A.cc"); > + Cmd.Directory = testPath("root"); > + Cmd.CommandLine = {"clang++", testPath("root/A.cc")}; > + // Check nothing is loaded from Storage, but A.cc and A.h has been stored. > + { > + OverlayCDB CDB(/*Base=*/nullptr); > + BackgroundIndex Idx(Context::empty(), "", FS, CDB, > + [&](llvm::StringRef) { return &MSS; }); > + CDB.setCompileCommand(testPath("root/A.cc"), Cmd); > + ASSERT_TRUE(Idx.blockUntilIdleForTest()); > + } > + > + // Change header. > + FS.Files[testPath("root/A.h")] = R"cpp( > + void common(); > + void f_b(); > + class A_CC {}; > + class A_CCnew {}; > + )cpp"; > + { > + OverlayCDB CDB(/*Base=*/nullptr); > + BackgroundIndex Idx(Context::empty(), "", FS, CDB, > + [&](llvm::StringRef) { return &MSS; }); > + CDB.setCompileCommand(testPath("root"), Cmd); > + ASSERT_TRUE(Idx.blockUntilIdleForTest()); > + } > + EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache. > + > + // Check if the new symbol has arrived. > + auto ShardHeader = MSS.loadShard(testPath("root/A.h")); > + EXPECT_NE(ShardHeader, nullptr); > + EXPECT_THAT(*ShardHeader->Symbols, Contains(Named("A_CCnew"))); > + > + // Change source. > + FS.Files[testPath("root/A.cc")] = > + "#include \"A.h\"\nvoid g() { (void)common; }\nvoid f_b() {}"; > + { > + CacheHits = 0; > + OverlayCDB CDB(/*Base=*/nullptr); > + BackgroundIndex Idx(Context::empty(), "", FS, CDB, > + [&](llvm::StringRef) { return &MSS; }); > + CDB.setCompileCommand(testPath("root"), Cmd); > + ASSERT_TRUE(Idx.blockUntilIdleForTest()); > + } > + EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache. > + > + // Check if the new symbol has arrived. > + auto ShardSource = MSS.loadShard(testPath("root/A.cc")); > + EXPECT_NE(ShardHeader, nullptr); > + EXPECT_THAT(*ShardSource->Symbols, > + Contains(AllOf(Named("f_b"), Declared(), Defined()))); > +} > + > } // namespace clangd > } // namespace clang > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits