TEST(MergeIndexTest, Refs) { FileIndex Dyn({"unittest"}); FileIndex StaticIndex({"unittest"}); auto MergedIndex = mergeIndex(&Dyn, &StaticIndex); const char *HeaderCode = "class Foo;"; auto HeaderSymbols = TestTU::withHeaderCode("class Foo;").headerSymbols(); auto Foo = findSymbol(HeaderSymbols, "Foo"); // Build dynamic index for test.cc. Annotations Test1Code(R"(class $Foo[[Foo]];)"); TestTU Test; Test.HeaderCode = HeaderCode; Test.Code = Test1Code.code(); Test.Filename = "test.cc"; auto AST = Test.build(); Dyn.update(Test.Filename, &AST.getASTContext(), AST.getPreprocessorPtr(), AST.getLocalTopLevelDecls()); // Build static index for test.cc. Test.HeaderCode = HeaderCode; Test.Code = "// static\nclass Foo {};"; Test.Filename = "test.cc"; auto StaticAST = Test.build(); // Add stale refs for test.cc. StaticIndex.update(Test.Filename, &StaticAST.getASTContext(), StaticAST.getPreprocessorPtr(), StaticAST.getLocalTopLevelDecls()); // Add refs for test2.cc Annotations Test2Code(R"(class $Foo[[Foo]] {};)"); TestTU Test2; Test2.HeaderCode = HeaderCode; Test2.Code = Test2Code.code(); Test2.Filename = "test2.cc"; StaticAST = Test2.build(); StaticIndex.update(Test2.Filename, &StaticAST.getASTContext(), StaticAST.getPreprocessorPtr(), StaticAST.getLocalTopLevelDecls()); RefsRequest Request; Request.IDs = {Foo.ID}; RefSlab::Builder Results; MergedIndex->refs(Request, [&](const Ref &O) { Results.insert(Foo.ID, O); }); EXPECT_THAT( std::move(Results).build(), ElementsAre(Pair( _, UnorderedElementsAre(AllOf(RefRange(Test1Code.range("Foo")), FileURI("unittest:///test.cc")), AllOf(RefRange(Test2Code.range("Foo")), FileURI("unittest:///test2.cc")))))); }
llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) { auto RIFF = riff::readFile(Data); if (!RIFF) return RIFF.takeError(); if (RIFF->Type != riff::fourCC("CdIx")) return makeError("wrong RIFF type"); llvm::StringMap<llvm::StringRef> Chunks; for (const auto &Chunk : RIFF->Chunks) Chunks.try_emplace(llvm::StringRef(Chunk.ID.data(), Chunk.ID.size()), Chunk.Data); for (llvm::StringRef RequiredChunk : {"meta", "stri"}) if (!Chunks.count(RequiredChunk)) return makeError("missing required chunk " + RequiredChunk); Reader Meta(Chunks.lookup("meta")); if (Meta.consume32() != Version) return makeError("wrong version"); auto Strings = readStringTable(Chunks.lookup("stri")); if (!Strings) return Strings.takeError(); IndexFileIn Result; if (Chunks.count("srcs")) { Reader SrcsReader(Chunks.lookup("srcs")); Result.Sources.emplace(); while (!SrcsReader.eof()) { auto IGN = readIncludeGraphNode(SrcsReader, Strings->Strings); auto Entry = Result.Sources->try_emplace(IGN.URI).first; Entry->getValue() = std::move(IGN); // We change all the strings inside the structure to point at the keys in // the map, since it is the only copy of the string that's going to live. Entry->getValue().URI = Entry->getKey(); for (auto &Include : Entry->getValue().DirectIncludes) Include = Result.Sources->try_emplace(Include).first->getKey(); } if (SrcsReader.err()) return makeError("malformed or truncated include uri"); } if (Chunks.count("symb")) { Reader SymbolReader(Chunks.lookup("symb")); SymbolSlab::Builder Symbols; while (!SymbolReader.eof()) Symbols.insert(readSymbol(SymbolReader, Strings->Strings)); if (SymbolReader.err()) return makeError("malformed or truncated symbol"); Result.Symbols = std::move(Symbols).build(); } if (Chunks.count("refs")) { Reader RefsReader(Chunks.lookup("refs")); RefSlab::Builder Refs; while (!RefsReader.eof()) { auto RefsBundle = readRefs(RefsReader, Strings->Strings); for (const auto &Ref : RefsBundle.second) // FIXME: bulk insert? Refs.insert(RefsBundle.first, Ref); } if (RefsReader.err()) return makeError("malformed or truncated refs"); Result.Refs = std::move(Refs).build(); } return std::move(Result); }