Author: Kirill Bobyrev Date: 2021-09-30T14:41:27+02:00 New Revision: dea48079b90d40f2087435b778544dffb0ab1793
URL: https://github.com/llvm/llvm-project/commit/dea48079b90d40f2087435b778544dffb0ab1793 DIFF: https://github.com/llvm/llvm-project/commit/dea48079b90d40f2087435b778544dffb0ab1793.diff LOG: [clangd] Land D110386 again This time, use llvm::sys::fs::UniqueID instead of unstable FileEntry::getName(), this should solve the problems on Windows and elsewhere. Added: Modified: clang-tools-extra/clangd/CodeComplete.cpp clang-tools-extra/clangd/Headers.cpp clang-tools-extra/clangd/Headers.h clang-tools-extra/clangd/unittests/HeadersTests.cpp clang-tools-extra/clangd/unittests/ParsedASTTests.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 69338814ebdd2..512959316e18e 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1379,14 +1379,17 @@ class CodeCompleteFlow { FileDistanceOptions ProxOpts{}; // Use defaults. const auto &SM = Recorder->CCSema->getSourceManager(); llvm::StringMap<SourceParams> ProxSources; - for (auto &Entry : Includes.includeDepth( - SM.getFileEntryForID(SM.getMainFileID())->getName())) { - auto &Source = ProxSources[Entry.getKey()]; - Source.Cost = Entry.getValue() * ProxOpts.IncludeCost; + auto MainFileID = + Includes.getID(SM.getFileEntryForID(SM.getMainFileID()), SM); + assert(MainFileID); + for (auto &HeaderIDAndDepth : Includes.includeDepth(*MainFileID)) { + auto &Source = + ProxSources[Includes.getRealPath(HeaderIDAndDepth.getFirst())]; + Source.Cost = HeaderIDAndDepth.getSecond() * ProxOpts.IncludeCost; // Symbols near our transitive includes are good, but only consider // things in the same directory or below it. Otherwise there can be // many false positives. - if (Entry.getValue() > 0) + if (HeaderIDAndDepth.getSecond() > 0) Source.MaxUpTraversals = 1; } FileProximity.emplace(ProxSources, ProxOpts); diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp index 111b05849b81b..ea07e050e9383 100644 --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -67,8 +67,9 @@ class RecordHeaders : public PPCallbacks { // Treat as if included from the main file. IncludingFileEntry = SM.getFileEntryForID(MainFID); } - Out->recordInclude(IncludingFileEntry->getName(), File->getName(), - File->tryGetRealPathName()); + auto IncludingID = Out->getOrCreateID(IncludingFileEntry, SM), + IncludedID = Out->getOrCreateID(File, SM); + Out->IncludeChildren[IncludingID].push_back(IncludedID); } } @@ -154,38 +155,52 @@ collectIncludeStructureCallback(const SourceManager &SM, return std::make_unique<RecordHeaders>(SM, Out); } -void IncludeStructure::recordInclude(llvm::StringRef IncludingName, - llvm::StringRef IncludedName, - llvm::StringRef IncludedRealName) { - auto Child = fileIndex(IncludedName); - if (!IncludedRealName.empty() && RealPathNames[Child].empty()) - RealPathNames[Child] = std::string(IncludedRealName); - auto Parent = fileIndex(IncludingName); - IncludeChildren[Parent].push_back(Child); +llvm::Optional<IncludeStructure::HeaderID> +IncludeStructure::getID(const FileEntry *Entry, + const SourceManager &SM) const { + // HeaderID of the main file is always 0; + if (SM.getMainFileID() == SM.translateFile(Entry)) { + return static_cast<IncludeStructure::HeaderID>(0u); + } + auto It = UIDToIndex.find(Entry->getUniqueID()); + if (It == UIDToIndex.end()) + return llvm::None; + return It->second; } -unsigned IncludeStructure::fileIndex(llvm::StringRef Name) { - auto R = NameToIndex.try_emplace(Name, RealPathNames.size()); +IncludeStructure::HeaderID +IncludeStructure::getOrCreateID(const FileEntry *Entry, + const SourceManager &SM) { + // Main file's FileID was not known at IncludeStructure creation time. + if (SM.getMainFileID() == SM.translateFile(Entry)) { + UIDToIndex[Entry->getUniqueID()] = + static_cast<IncludeStructure::HeaderID>(0u); + } + auto R = UIDToIndex.try_emplace( + Entry->getUniqueID(), + static_cast<IncludeStructure::HeaderID>(RealPathNames.size())); if (R.second) RealPathNames.emplace_back(); - return R.first->getValue(); + IncludeStructure::HeaderID Result = R.first->getSecond(); + std::string &RealPathName = RealPathNames[static_cast<unsigned>(Result)]; + if (RealPathName.empty()) + RealPathName = Entry->tryGetRealPathName().str(); + return Result; } -llvm::StringMap<unsigned> -IncludeStructure::includeDepth(llvm::StringRef Root) const { +llvm::DenseMap<IncludeStructure::HeaderID, unsigned> +IncludeStructure::includeDepth(HeaderID Root) const { // Include depth 0 is the main file only. - llvm::StringMap<unsigned> Result; + llvm::DenseMap<HeaderID, unsigned> Result; + assert(static_cast<unsigned>(Root) < RealPathNames.size()); Result[Root] = 0; - std::vector<unsigned> CurrentLevel; - llvm::DenseSet<unsigned> Seen; - auto It = NameToIndex.find(Root); - if (It != NameToIndex.end()) { - CurrentLevel.push_back(It->second); - Seen.insert(It->second); - } + std::vector<IncludeStructure::HeaderID> CurrentLevel; + CurrentLevel.push_back(Root); + llvm::DenseSet<IncludeStructure::HeaderID> Seen; + Seen.insert(Root); // Each round of BFS traversal finds the next depth level. - std::vector<unsigned> PreviousLevel; + std::vector<IncludeStructure::HeaderID> PreviousLevel; for (unsigned Level = 1; !CurrentLevel.empty(); ++Level) { PreviousLevel.clear(); PreviousLevel.swap(CurrentLevel); @@ -193,10 +208,7 @@ IncludeStructure::includeDepth(llvm::StringRef Root) const { for (const auto &Child : IncludeChildren.lookup(Parent)) { if (Seen.insert(Child).second) { CurrentLevel.push_back(Child); - const auto &Name = RealPathNames[Child]; - // Can't include files if we don't have their real path. - if (!Name.empty()) - Result[Name] = Level; + Result[Child] = Level; } } } diff --git a/clang-tools-extra/clangd/Headers.h b/clang-tools-extra/clangd/Headers.h index f4ca364880c41..fa24d43e9bff1 100644 --- a/clang-tools-extra/clangd/Headers.h +++ b/clang-tools-extra/clangd/Headers.h @@ -12,6 +12,7 @@ #include "Protocol.h" #include "SourceCode.h" #include "index/Symbol.h" +#include "support/Logger.h" #include "support/Path.h" #include "clang/Basic/TokenKinds.h" #include "clang/Format/Format.h" @@ -22,6 +23,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem/UniqueID.h" #include "llvm/Support/VirtualFileSystem.h" #include <string> @@ -62,7 +64,7 @@ struct Inclusion { llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Inclusion &); bool operator==(const Inclusion &LHS, const Inclusion &RHS); -// Contains information about one file in the build grpah and its direct +// Contains information about one file in the build graph and its direct // dependencies. Doesn't own the strings it references (IncludeGraph is // self-contained). struct IncludeGraphNode { @@ -112,7 +114,25 @@ operator|=(IncludeGraphNode::SourceFlag &A, IncludeGraphNode::SourceFlag B) { // in any non-preamble inclusions. class IncludeStructure { public: - std::vector<Inclusion> MainFileIncludes; + IncludeStructure() { + // Reserve HeaderID = 0 for the main file. + RealPathNames.emplace_back(); + } + + // HeaderID identifies file in the include graph. It corresponds to a + // FileEntry rather than a FileID, but stays stable across preamble & main + // file builds. + enum class HeaderID : unsigned {}; + + llvm::Optional<HeaderID> getID(const FileEntry *Entry, + const SourceManager &SM) const; + HeaderID getOrCreateID(const FileEntry *Entry, + const SourceManager &SM); + + StringRef getRealPath(HeaderID ID) const { + assert(static_cast<unsigned>(ID) <= RealPathNames.size()); + return RealPathNames[static_cast<unsigned>(ID)]; + } // Return all transitively reachable files. llvm::ArrayRef<std::string> allHeaders() const { return RealPathNames; } @@ -120,26 +140,27 @@ class IncludeStructure { // Return all transitively reachable files, and their minimum include depth. // All transitive includes (absolute paths), with their minimum include depth. // Root --> 0, #included file --> 1, etc. - // Root is clang's name for a file, which may not be absolute. - // Usually it should be SM.getFileEntryForID(SM.getMainFileID())->getName(). - llvm::StringMap<unsigned> includeDepth(llvm::StringRef Root) const; + // Root is the ID of the header being visited first. + // Usually it is getID(SM.getFileEntryForID(SM.getMainFileID())->getName()). + llvm::DenseMap<HeaderID, unsigned> includeDepth(HeaderID Root) const; - // This updates IncludeDepth(), but not MainFileIncludes. - void recordInclude(llvm::StringRef IncludingName, - llvm::StringRef IncludedName, - llvm::StringRef IncludedRealName); + // Maps HeaderID to the ids of the files included from it. + llvm::DenseMap<HeaderID, SmallVector<HeaderID>> IncludeChildren; + + std::vector<Inclusion> MainFileIncludes; private: + std::vector<std::string> RealPathNames; // In HeaderID order. + // HeaderID maps the FileEntry::UniqueID to the internal representation. // Identifying files in a way that persists from preamble build to subsequent - // builds is surprisingly hard. FileID is unavailable in InclusionDirective(), - // and RealPathName and UniqueID are not preserved in the preamble. - // We use the FileEntry::Name, which is stable, interned into a "file index". - // The paths we want to expose are the RealPathName, so store those too. - std::vector<std::string> RealPathNames; // In file index order. - unsigned fileIndex(llvm::StringRef Name); - llvm::StringMap<unsigned> NameToIndex; // Values are file indexes. - // Maps a file's index to that of the files it includes. - llvm::DenseMap<unsigned, llvm::SmallVector<unsigned>> IncludeChildren; + // builds is surprisingly hard. FileID is unavailable in + // InclusionDirective(), and RealPathName and UniqueID are not preserved in + // the preamble. + // + // We reserve 0 to the main file and will manually check for that in getID + // and getOrCreateID because llvm::sys::fs::UniqueID is not stable when their + // content of the main file changes. + llvm::DenseMap<llvm::sys::fs::UniqueID, HeaderID> UIDToIndex; }; /// Returns a PPCallback that visits all inclusions in the main file. @@ -205,4 +226,55 @@ class IncludeInserter { } // namespace clangd } // namespace clang +namespace llvm { + +// Support Tokens as DenseMap keys. +template <> struct DenseMapInfo<clang::clangd::IncludeStructure::HeaderID> { + static inline clang::clangd::IncludeStructure::HeaderID getEmptyKey() { + return static_cast<clang::clangd::IncludeStructure::HeaderID>( + DenseMapInfo<unsigned>::getEmptyKey()); + } + + static inline clang::clangd::IncludeStructure::HeaderID getTombstoneKey() { + return static_cast<clang::clangd::IncludeStructure::HeaderID>( + DenseMapInfo<unsigned>::getTombstoneKey()); + } + + static unsigned + getHashValue(const clang::clangd::IncludeStructure::HeaderID &Tag) { + return hash_value(static_cast<unsigned>(Tag)); + } + + static bool isEqual(const clang::clangd::IncludeStructure::HeaderID &LHS, + const clang::clangd::IncludeStructure::HeaderID &RHS) { + return LHS == RHS; + } +}; + +// Support Tokens as DenseMap keys. +template <> struct DenseMapInfo<llvm::sys::fs::UniqueID> { + static inline llvm::sys::fs::UniqueID getEmptyKey() { + auto EmptyKey = DenseMapInfo<std::pair<unsigned, unsigned>>::getEmptyKey(); + return {EmptyKey.first, EmptyKey.second}; + } + + static inline llvm::sys::fs::UniqueID getTombstoneKey() { + auto TombstoneKey = + DenseMapInfo<std::pair<unsigned, unsigned>>::getTombstoneKey(); + return {TombstoneKey.first, TombstoneKey.second}; + } + + static unsigned getHashValue(const llvm::sys::fs::UniqueID &Tag) { + return hash_value( + std::pair<unsigned, unsigned>(Tag.getDevice(), Tag.getFile())); + } + + static bool isEqual(const llvm::sys::fs::UniqueID &LHS, + const llvm::sys::fs::UniqueID &RHS) { + return LHS == RHS; + } +}; + +} // namespace llvm + #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEADERS_H diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp index 13babb89a3ee3..bee3d181cf80d 100644 --- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp @@ -17,6 +17,7 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Lex/PreprocessorOptions.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "gmock/gmock.h" @@ -29,8 +30,10 @@ namespace { using ::testing::AllOf; using ::testing::Contains; using ::testing::ElementsAre; +using ::testing::IsEmpty; using ::testing::Not; using ::testing::UnorderedElementsAre; +using ::testing::UnorderedElementsAreArray; class HeadersTest : public ::testing::Test { public: @@ -64,8 +67,16 @@ class HeadersTest : public ::testing::Test { } protected: + IncludeStructure::HeaderID getID(StringRef Filename, + IncludeStructure &Includes) { + auto &SM = Clang->getSourceManager(); + auto Entry = SM.getFileManager().getFile(Filename); + EXPECT_TRUE(Entry); + return Includes.getOrCreateID(*Entry, SM); + } + IncludeStructure collectIncludes() { - auto Clang = setupClang(); + Clang = setupClang(); PreprocessOnlyAction Action; EXPECT_TRUE( Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])); @@ -81,7 +92,7 @@ class HeadersTest : public ::testing::Test { // inserted. std::string calculate(PathRef Original, PathRef Preferred = "", const std::vector<Inclusion> &Inclusions = {}) { - auto Clang = setupClang(); + Clang = setupClang(); PreprocessOnlyAction Action; EXPECT_TRUE( Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])); @@ -107,7 +118,7 @@ class HeadersTest : public ::testing::Test { } llvm::Optional<TextEdit> insert(llvm::StringRef VerbatimHeader) { - auto Clang = setupClang(); + Clang = setupClang(); PreprocessOnlyAction Action; EXPECT_TRUE( Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])); @@ -126,6 +137,7 @@ class HeadersTest : public ::testing::Test { std::string Subdir = testPath("sub"); std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str(); IgnoringDiagConsumer IgnoreDiags; + std::unique_ptr<CompilerInstance> Clang; }; MATCHER_P(Written, Name, "") { return arg.Written == Name; } @@ -134,11 +146,11 @@ MATCHER_P(IncludeLine, N, "") { return arg.HashLine == N; } MATCHER_P(Directive, D, "") { return arg.Directive == D; } MATCHER_P2(Distance, File, D, "") { - if (arg.getKey() != File) - *result_listener << "file =" << arg.getKey().str(); - if (arg.getValue() != D) - *result_listener << "distance =" << arg.getValue(); - return arg.getKey() == File && arg.getValue() == D; + if (arg.getFirst() != File) + *result_listener << "file =" << static_cast<unsigned>(arg.getFirst()); + if (arg.getSecond() != D) + *result_listener << "distance =" << arg.getSecond(); + return arg.getFirst() == File && arg.getSecond() == D; } TEST_F(HeadersTest, CollectRewrittenAndResolved) { @@ -148,12 +160,13 @@ TEST_F(HeadersTest, CollectRewrittenAndResolved) { std::string BarHeader = testPath("sub/bar.h"); FS.Files[BarHeader] = ""; - EXPECT_THAT(collectIncludes().MainFileIncludes, + auto Includes = collectIncludes(); + EXPECT_THAT(Includes.MainFileIncludes, UnorderedElementsAre( AllOf(Written("\"sub/bar.h\""), Resolved(BarHeader)))); - EXPECT_THAT(collectIncludes().includeDepth(MainFile), - UnorderedElementsAre(Distance(MainFile, 0u), - Distance(testPath("sub/bar.h"), 1u))); + EXPECT_THAT(Includes.includeDepth(getID(MainFile, Includes)), + UnorderedElementsAre(Distance(getID(MainFile, Includes), 0u), + Distance(getID(BarHeader, Includes), 1u))); } TEST_F(HeadersTest, OnlyCollectInclusionsInMain) { @@ -166,17 +179,18 @@ TEST_F(HeadersTest, OnlyCollectInclusionsInMain) { FS.Files[MainFile] = R"cpp( #include "bar.h" )cpp"; - EXPECT_THAT( - collectIncludes().MainFileIncludes, - UnorderedElementsAre(AllOf(Written("\"bar.h\""), Resolved(BarHeader)))); - EXPECT_THAT(collectIncludes().includeDepth(MainFile), - UnorderedElementsAre(Distance(MainFile, 0u), - Distance(testPath("sub/bar.h"), 1u), - Distance(testPath("sub/baz.h"), 2u))); + auto Includes = collectIncludes(); + EXPECT_THAT(Includes.MainFileIncludes, + UnorderedElementsAre( + AllOf(Written("\"bar.h\""), Resolved(BarHeader)))); + EXPECT_THAT(Includes.includeDepth(getID(MainFile, Includes)), + UnorderedElementsAre(Distance(getID(MainFile, Includes), 0u), + Distance(getID(BarHeader, Includes), 1u), + Distance(getID(BazHeader, Includes), 2u))); // includeDepth() also works for non-main files. - EXPECT_THAT(collectIncludes().includeDepth(testPath("sub/bar.h")), - UnorderedElementsAre(Distance(testPath("sub/bar.h"), 0u), - Distance(testPath("sub/baz.h"), 1u))); + EXPECT_THAT(Includes.includeDepth(getID(BarHeader, Includes)), + UnorderedElementsAre(Distance(getID(BarHeader, Includes), 0u), + Distance(getID(BazHeader, Includes), 1u))); } TEST_F(HeadersTest, PreambleIncludesPresentOnce) { @@ -202,8 +216,32 @@ TEST_F(HeadersTest, UnResolvedInclusion) { EXPECT_THAT(collectIncludes().MainFileIncludes, UnorderedElementsAre(AllOf(Written("\"foo.h\""), Resolved("")))); - EXPECT_THAT(collectIncludes().includeDepth(MainFile), - UnorderedElementsAre(Distance(MainFile, 0u))); + EXPECT_THAT(collectIncludes().IncludeChildren, IsEmpty()); +} + +TEST_F(HeadersTest, IncludedFilesGraph) { + FS.Files[MainFile] = R"cpp( +#include "bar.h" +#include "foo.h" +)cpp"; + std::string BarHeader = testPath("bar.h"); + FS.Files[BarHeader] = ""; + std::string FooHeader = testPath("foo.h"); + FS.Files[FooHeader] = R"cpp( +#include "bar.h" +#include "baz.h" +)cpp"; + std::string BazHeader = testPath("baz.h"); + FS.Files[BazHeader] = ""; + + auto Includes = collectIncludes(); + llvm::DenseMap<IncludeStructure::HeaderID, + SmallVector<IncludeStructure::HeaderID>> + Expected = {{getID(MainFile, Includes), + {getID(BarHeader, Includes), getID(FooHeader, Includes)}}, + {getID(FooHeader, Includes), + {getID(BarHeader, Includes), getID(BazHeader, Includes)}}}; + EXPECT_EQ(Includes.IncludeChildren, Expected); } TEST_F(HeadersTest, IncludeDirective) { diff --git a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp index 7288acbcd4697..67cd18ab01157 100644 --- a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp @@ -44,9 +44,11 @@ namespace clangd { namespace { using ::testing::AllOf; +using ::testing::Contains; using ::testing::ElementsAre; using ::testing::ElementsAreArray; using ::testing::IsEmpty; +using ::testing::UnorderedElementsAreArray; MATCHER_P(DeclNamed, Name, "") { if (NamedDecl *ND = dyn_cast<NamedDecl>(arg)) @@ -493,7 +495,7 @@ TEST(ParsedASTTest, PatchesAdditionalIncludes) { auto EmptyPreamble = buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr); ASSERT_TRUE(EmptyPreamble); - EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, testing::IsEmpty()); + EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, IsEmpty()); // Now build an AST using empty preamble and ensure patched includes worked. TU.Code = ModifiedContents.str(); @@ -507,18 +509,18 @@ TEST(ParsedASTTest, PatchesAdditionalIncludes) { EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes, testing::Pointwise( EqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes)); - auto StringMapToVector = [](const llvm::StringMap<unsigned> SM) { - std::vector<std::pair<std::string, unsigned>> Res; - for (const auto &E : SM) - Res.push_back({E.first().str(), E.second}); - llvm::sort(Res); - return Res; - }; // Ensure file proximity signals are correct. - EXPECT_EQ(StringMapToVector(PatchedAST->getIncludeStructure().includeDepth( - testPath("foo.cpp"))), - StringMapToVector(ExpectedAST.getIncludeStructure().includeDepth( - testPath("foo.cpp")))); + auto &SM = PatchedAST->getSourceManager(); + auto &FM = SM.getFileManager(); + // Copy so that we can use operator[] to get the children. + IncludeStructure Includes = PatchedAST->getIncludeStructure(); + auto MainFE = FM.getFile(testPath("foo.cpp")); + ASSERT_TRUE(MainFE); + auto MainID = Includes.getID(*MainFE, SM); + auto AuxFE = FM.getFile(testPath("sub/aux.h")); + ASSERT_TRUE(AuxFE); + auto AuxID = Includes.getID(*AuxFE, SM); + EXPECT_THAT(Includes.IncludeChildren[*MainID], Contains(*AuxID)); } TEST(ParsedASTTest, PatchesDeletedIncludes) { @@ -551,18 +553,21 @@ TEST(ParsedASTTest, PatchesDeletedIncludes) { EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes, testing::Pointwise( EqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes)); - auto StringMapToVector = [](const llvm::StringMap<unsigned> SM) { - std::vector<std::pair<std::string, unsigned>> Res; - for (const auto &E : SM) - Res.push_back({E.first().str(), E.second}); - llvm::sort(Res); - return Res; - }; // Ensure file proximity signals are correct. - EXPECT_EQ(StringMapToVector(PatchedAST->getIncludeStructure().includeDepth( - testPath("foo.cpp"))), - StringMapToVector(ExpectedAST.getIncludeStructure().includeDepth( - testPath("foo.cpp")))); + auto &SM = ExpectedAST.getSourceManager(); + auto &FM = SM.getFileManager(); + // Copy so that we can getOrCreateID(). + IncludeStructure Includes = ExpectedAST.getIncludeStructure(); + auto MainFE = FM.getFile(testPath("foo.cpp")); + ASSERT_TRUE(MainFE); + auto MainID = Includes.getOrCreateID(*MainFE, SM); + auto &PatchedFM = PatchedAST->getSourceManager().getFileManager(); + IncludeStructure PatchedIncludes = PatchedAST->getIncludeStructure(); + auto PatchedMainFE = PatchedFM.getFile(testPath("foo.cpp")); + ASSERT_TRUE(PatchedMainFE); + auto PatchedMainID = PatchedIncludes.getOrCreateID(*PatchedMainFE, SM); + EXPECT_EQ(Includes.includeDepth(MainID)[MainID], + PatchedIncludes.includeDepth(PatchedMainID)[PatchedMainID]); } // Returns Code guarded by #ifndef guards _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits