forked from OSchip/llvm-project
Revert "[clangd] Refactor IncludeStructure: use File (unsigned) for most computations"
This reverts commit 0b1eff1bc5
.
Breaks check-clangd on Windows, see comments on
https://reviews.llvm.org/D110386
This commit is contained in:
parent
80fa43fe9a
commit
36dc5c048a
|
@ -1379,16 +1379,14 @@ public:
|
||||||
FileDistanceOptions ProxOpts{}; // Use defaults.
|
FileDistanceOptions ProxOpts{}; // Use defaults.
|
||||||
const auto &SM = Recorder->CCSema->getSourceManager();
|
const auto &SM = Recorder->CCSema->getSourceManager();
|
||||||
llvm::StringMap<SourceParams> ProxSources;
|
llvm::StringMap<SourceParams> ProxSources;
|
||||||
auto MainFileID =
|
for (auto &Entry : Includes.includeDepth(
|
||||||
Includes.getOrCreateID(SM.getFileEntryForID(SM.getMainFileID()));
|
SM.getFileEntryForID(SM.getMainFileID())->getName())) {
|
||||||
for (auto &HeaderIDAndDepth : Includes.includeDepth(MainFileID)) {
|
auto &Source = ProxSources[Entry.getKey()];
|
||||||
auto &Source =
|
Source.Cost = Entry.getValue() * ProxOpts.IncludeCost;
|
||||||
ProxSources[Includes.getRealPath(HeaderIDAndDepth.getFirst())];
|
|
||||||
Source.Cost = HeaderIDAndDepth.getSecond() * ProxOpts.IncludeCost;
|
|
||||||
// Symbols near our transitive includes are good, but only consider
|
// Symbols near our transitive includes are good, but only consider
|
||||||
// things in the same directory or below it. Otherwise there can be
|
// things in the same directory or below it. Otherwise there can be
|
||||||
// many false positives.
|
// many false positives.
|
||||||
if (HeaderIDAndDepth.getSecond() > 0)
|
if (Entry.getValue() > 0)
|
||||||
Source.MaxUpTraversals = 1;
|
Source.MaxUpTraversals = 1;
|
||||||
}
|
}
|
||||||
FileProximity.emplace(ProxSources, ProxOpts);
|
FileProximity.emplace(ProxSources, ProxOpts);
|
||||||
|
|
|
@ -67,9 +67,8 @@ public:
|
||||||
// Treat as if included from the main file.
|
// Treat as if included from the main file.
|
||||||
IncludingFileEntry = SM.getFileEntryForID(MainFID);
|
IncludingFileEntry = SM.getFileEntryForID(MainFID);
|
||||||
}
|
}
|
||||||
auto IncludingID = Out->getOrCreateID(IncludingFileEntry),
|
Out->recordInclude(IncludingFileEntry->getName(), File->getName(),
|
||||||
IncludedID = Out->getOrCreateID(File);
|
File->tryGetRealPathName());
|
||||||
Out->IncludeChildren[IncludingID].push_back(IncludedID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,41 +154,38 @@ collectIncludeStructureCallback(const SourceManager &SM,
|
||||||
return std::make_unique<RecordHeaders>(SM, Out);
|
return std::make_unique<RecordHeaders>(SM, Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Optional<IncludeStructure::HeaderID>
|
void IncludeStructure::recordInclude(llvm::StringRef IncludingName,
|
||||||
IncludeStructure::getID(const FileEntry *Entry) const {
|
llvm::StringRef IncludedName,
|
||||||
auto It = NameToIndex.find(Entry->getName());
|
llvm::StringRef IncludedRealName) {
|
||||||
if (It == NameToIndex.end())
|
auto Child = fileIndex(IncludedName);
|
||||||
return llvm::None;
|
if (!IncludedRealName.empty() && RealPathNames[Child].empty())
|
||||||
return It->second;
|
RealPathNames[Child] = std::string(IncludedRealName);
|
||||||
|
auto Parent = fileIndex(IncludingName);
|
||||||
|
IncludeChildren[Parent].push_back(Child);
|
||||||
}
|
}
|
||||||
|
|
||||||
IncludeStructure::HeaderID
|
unsigned IncludeStructure::fileIndex(llvm::StringRef Name) {
|
||||||
IncludeStructure::getOrCreateID(const FileEntry *Entry) {
|
auto R = NameToIndex.try_emplace(Name, RealPathNames.size());
|
||||||
auto R = NameToIndex.try_emplace(
|
|
||||||
Entry->getName(),
|
|
||||||
static_cast<IncludeStructure::HeaderID>(RealPathNames.size()));
|
|
||||||
if (R.second)
|
if (R.second)
|
||||||
RealPathNames.emplace_back();
|
RealPathNames.emplace_back();
|
||||||
IncludeStructure::HeaderID Result = R.first->getValue();
|
return R.first->getValue();
|
||||||
std::string &RealPathName = RealPathNames[static_cast<unsigned>(Result)];
|
|
||||||
if (RealPathName.empty())
|
|
||||||
RealPathName = Entry->tryGetRealPathName().str();
|
|
||||||
return Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::DenseMap<IncludeStructure::HeaderID, unsigned>
|
llvm::StringMap<unsigned>
|
||||||
IncludeStructure::includeDepth(HeaderID Root) const {
|
IncludeStructure::includeDepth(llvm::StringRef Root) const {
|
||||||
// Include depth 0 is the main file only.
|
// Include depth 0 is the main file only.
|
||||||
llvm::DenseMap<HeaderID, unsigned> Result;
|
llvm::StringMap<unsigned> Result;
|
||||||
assert(static_cast<unsigned>(Root) < RealPathNames.size());
|
|
||||||
Result[Root] = 0;
|
Result[Root] = 0;
|
||||||
std::vector<IncludeStructure::HeaderID> CurrentLevel;
|
std::vector<unsigned> CurrentLevel;
|
||||||
CurrentLevel.push_back(Root);
|
llvm::DenseSet<unsigned> Seen;
|
||||||
llvm::DenseSet<IncludeStructure::HeaderID> Seen;
|
auto It = NameToIndex.find(Root);
|
||||||
Seen.insert(Root);
|
if (It != NameToIndex.end()) {
|
||||||
|
CurrentLevel.push_back(It->second);
|
||||||
|
Seen.insert(It->second);
|
||||||
|
}
|
||||||
|
|
||||||
// Each round of BFS traversal finds the next depth level.
|
// Each round of BFS traversal finds the next depth level.
|
||||||
std::vector<IncludeStructure::HeaderID> PreviousLevel;
|
std::vector<unsigned> PreviousLevel;
|
||||||
for (unsigned Level = 1; !CurrentLevel.empty(); ++Level) {
|
for (unsigned Level = 1; !CurrentLevel.empty(); ++Level) {
|
||||||
PreviousLevel.clear();
|
PreviousLevel.clear();
|
||||||
PreviousLevel.swap(CurrentLevel);
|
PreviousLevel.swap(CurrentLevel);
|
||||||
|
@ -197,7 +193,10 @@ IncludeStructure::includeDepth(HeaderID Root) const {
|
||||||
for (const auto &Child : IncludeChildren.lookup(Parent)) {
|
for (const auto &Child : IncludeChildren.lookup(Parent)) {
|
||||||
if (Seen.insert(Child).second) {
|
if (Seen.insert(Child).second) {
|
||||||
CurrentLevel.push_back(Child);
|
CurrentLevel.push_back(Child);
|
||||||
Result[Child] = Level;
|
const auto &Name = RealPathNames[Child];
|
||||||
|
// Can't include files if we don't have their real path.
|
||||||
|
if (!Name.empty())
|
||||||
|
Result[Name] = Level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "Protocol.h"
|
#include "Protocol.h"
|
||||||
#include "SourceCode.h"
|
#include "SourceCode.h"
|
||||||
#include "index/Symbol.h"
|
#include "index/Symbol.h"
|
||||||
#include "support/Logger.h"
|
|
||||||
#include "support/Path.h"
|
#include "support/Path.h"
|
||||||
#include "clang/Basic/TokenKinds.h"
|
#include "clang/Basic/TokenKinds.h"
|
||||||
#include "clang/Format/Format.h"
|
#include "clang/Format/Format.h"
|
||||||
|
@ -63,7 +62,7 @@ struct Inclusion {
|
||||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Inclusion &);
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Inclusion &);
|
||||||
bool operator==(const Inclusion &LHS, const Inclusion &RHS);
|
bool operator==(const Inclusion &LHS, const Inclusion &RHS);
|
||||||
|
|
||||||
// Contains information about one file in the build graph and its direct
|
// Contains information about one file in the build grpah and its direct
|
||||||
// dependencies. Doesn't own the strings it references (IncludeGraph is
|
// dependencies. Doesn't own the strings it references (IncludeGraph is
|
||||||
// self-contained).
|
// self-contained).
|
||||||
struct IncludeGraphNode {
|
struct IncludeGraphNode {
|
||||||
|
@ -113,18 +112,7 @@ operator|=(IncludeGraphNode::SourceFlag &A, IncludeGraphNode::SourceFlag B) {
|
||||||
// in any non-preamble inclusions.
|
// in any non-preamble inclusions.
|
||||||
class IncludeStructure {
|
class IncludeStructure {
|
||||||
public:
|
public:
|
||||||
// HeaderID identifies file in the include graph. It corresponds to a
|
std::vector<Inclusion> MainFileIncludes;
|
||||||
// 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;
|
|
||||||
HeaderID getOrCreateID(const FileEntry *Entry);
|
|
||||||
|
|
||||||
StringRef getRealPath(HeaderID ID) const {
|
|
||||||
assert(static_cast<unsigned>(ID) <= RealPathNames.size());
|
|
||||||
return RealPathNames[static_cast<unsigned>(ID)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return all transitively reachable files.
|
// Return all transitively reachable files.
|
||||||
llvm::ArrayRef<std::string> allHeaders() const { return RealPathNames; }
|
llvm::ArrayRef<std::string> allHeaders() const { return RealPathNames; }
|
||||||
|
@ -132,23 +120,26 @@ public:
|
||||||
// Return all transitively reachable files, and their minimum include depth.
|
// Return all transitively reachable files, and their minimum include depth.
|
||||||
// All transitive includes (absolute paths), with their minimum include depth.
|
// All transitive includes (absolute paths), with their minimum include depth.
|
||||||
// Root --> 0, #included file --> 1, etc.
|
// Root --> 0, #included file --> 1, etc.
|
||||||
// Root is the ID of the header being visited first.
|
// Root is clang's name for a file, which may not be absolute.
|
||||||
// Usually it is getID(SM.getFileEntryForID(SM.getMainFileID())->getName()).
|
// Usually it should be SM.getFileEntryForID(SM.getMainFileID())->getName().
|
||||||
llvm::DenseMap<HeaderID, unsigned> includeDepth(HeaderID Root) const;
|
llvm::StringMap<unsigned> includeDepth(llvm::StringRef Root) const;
|
||||||
|
|
||||||
// Maps HeaderID to the ids of the files included from it.
|
// This updates IncludeDepth(), but not MainFileIncludes.
|
||||||
llvm::DenseMap<HeaderID, SmallVector<HeaderID>> IncludeChildren;
|
void recordInclude(llvm::StringRef IncludingName,
|
||||||
|
llvm::StringRef IncludedName,
|
||||||
std::vector<Inclusion> MainFileIncludes;
|
llvm::StringRef IncludedRealName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> RealPathNames; // In HeaderID order.
|
|
||||||
// HeaderID maps the FileEntry::Name to the internal representation.
|
|
||||||
// Identifying files in a way that persists from preamble build to subsequent
|
// Identifying files in a way that persists from preamble build to subsequent
|
||||||
// builds is surprisingly hard. FileID is unavailable in
|
// builds is surprisingly hard. FileID is unavailable in InclusionDirective(),
|
||||||
// InclusionDirective(), and RealPathName and UniqueID are not preserved in
|
// and RealPathName and UniqueID are not preserved in the preamble.
|
||||||
// the preamble.
|
// We use the FileEntry::Name, which is stable, interned into a "file index".
|
||||||
llvm::StringMap<HeaderID> NameToIndex;
|
// 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns a PPCallback that visits all inclusions in the main file.
|
/// Returns a PPCallback that visits all inclusions in the main file.
|
||||||
|
@ -214,31 +205,4 @@ private:
|
||||||
} // namespace clangd
|
} // namespace clangd
|
||||||
} // namespace clang
|
} // 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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace llvm
|
|
||||||
|
|
||||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEADERS_H
|
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEADERS_H
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "clang/Frontend/FrontendActions.h"
|
#include "clang/Frontend/FrontendActions.h"
|
||||||
#include "clang/Lex/PreprocessorOptions.h"
|
#include "clang/Lex/PreprocessorOptions.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Support/Error.h"
|
|
||||||
#include "llvm/Support/FormatVariadic.h"
|
#include "llvm/Support/FormatVariadic.h"
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
#include "gmock/gmock.h"
|
#include "gmock/gmock.h"
|
||||||
|
@ -30,10 +29,8 @@ namespace {
|
||||||
using ::testing::AllOf;
|
using ::testing::AllOf;
|
||||||
using ::testing::Contains;
|
using ::testing::Contains;
|
||||||
using ::testing::ElementsAre;
|
using ::testing::ElementsAre;
|
||||||
using ::testing::IsEmpty;
|
|
||||||
using ::testing::Not;
|
using ::testing::Not;
|
||||||
using ::testing::UnorderedElementsAre;
|
using ::testing::UnorderedElementsAre;
|
||||||
using ::testing::UnorderedElementsAreArray;
|
|
||||||
|
|
||||||
class HeadersTest : public ::testing::Test {
|
class HeadersTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
@ -67,15 +64,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
IncludeStructure::HeaderID getID(StringRef Filename,
|
|
||||||
IncludeStructure &Includes) {
|
|
||||||
auto Entry = Clang->getSourceManager().getFileManager().getFile(Filename);
|
|
||||||
EXPECT_TRUE(Entry);
|
|
||||||
return Includes.getOrCreateID(*Entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
IncludeStructure collectIncludes() {
|
IncludeStructure collectIncludes() {
|
||||||
Clang = setupClang();
|
auto Clang = setupClang();
|
||||||
PreprocessOnlyAction Action;
|
PreprocessOnlyAction Action;
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
|
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
|
||||||
|
@ -91,7 +81,7 @@ protected:
|
||||||
// inserted.
|
// inserted.
|
||||||
std::string calculate(PathRef Original, PathRef Preferred = "",
|
std::string calculate(PathRef Original, PathRef Preferred = "",
|
||||||
const std::vector<Inclusion> &Inclusions = {}) {
|
const std::vector<Inclusion> &Inclusions = {}) {
|
||||||
Clang = setupClang();
|
auto Clang = setupClang();
|
||||||
PreprocessOnlyAction Action;
|
PreprocessOnlyAction Action;
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
|
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
|
||||||
|
@ -117,7 +107,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Optional<TextEdit> insert(llvm::StringRef VerbatimHeader) {
|
llvm::Optional<TextEdit> insert(llvm::StringRef VerbatimHeader) {
|
||||||
Clang = setupClang();
|
auto Clang = setupClang();
|
||||||
PreprocessOnlyAction Action;
|
PreprocessOnlyAction Action;
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
|
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
|
||||||
|
@ -136,7 +126,6 @@ protected:
|
||||||
std::string Subdir = testPath("sub");
|
std::string Subdir = testPath("sub");
|
||||||
std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
|
std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
|
||||||
IgnoringDiagConsumer IgnoreDiags;
|
IgnoringDiagConsumer IgnoreDiags;
|
||||||
std::unique_ptr<CompilerInstance> Clang;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MATCHER_P(Written, Name, "") { return arg.Written == Name; }
|
MATCHER_P(Written, Name, "") { return arg.Written == Name; }
|
||||||
|
@ -145,11 +134,11 @@ MATCHER_P(IncludeLine, N, "") { return arg.HashLine == N; }
|
||||||
MATCHER_P(Directive, D, "") { return arg.Directive == D; }
|
MATCHER_P(Directive, D, "") { return arg.Directive == D; }
|
||||||
|
|
||||||
MATCHER_P2(Distance, File, D, "") {
|
MATCHER_P2(Distance, File, D, "") {
|
||||||
if (arg.getFirst() != File)
|
if (arg.getKey() != File)
|
||||||
*result_listener << "file =" << static_cast<unsigned>(arg.getFirst());
|
*result_listener << "file =" << arg.getKey().str();
|
||||||
if (arg.getSecond() != D)
|
if (arg.getValue() != D)
|
||||||
*result_listener << "distance =" << arg.getSecond();
|
*result_listener << "distance =" << arg.getValue();
|
||||||
return arg.getFirst() == File && arg.getSecond() == D;
|
return arg.getKey() == File && arg.getValue() == D;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HeadersTest, CollectRewrittenAndResolved) {
|
TEST_F(HeadersTest, CollectRewrittenAndResolved) {
|
||||||
|
@ -159,14 +148,12 @@ TEST_F(HeadersTest, CollectRewrittenAndResolved) {
|
||||||
std::string BarHeader = testPath("sub/bar.h");
|
std::string BarHeader = testPath("sub/bar.h");
|
||||||
FS.Files[BarHeader] = "";
|
FS.Files[BarHeader] = "";
|
||||||
|
|
||||||
auto Includes = collectIncludes();
|
EXPECT_THAT(collectIncludes().MainFileIncludes,
|
||||||
EXPECT_THAT(Includes.MainFileIncludes,
|
|
||||||
UnorderedElementsAre(
|
UnorderedElementsAre(
|
||||||
AllOf(Written("\"sub/bar.h\""), Resolved(BarHeader))));
|
AllOf(Written("\"sub/bar.h\""), Resolved(BarHeader))));
|
||||||
EXPECT_THAT(collectIncludes().includeDepth(getID(MainFile, Includes)),
|
EXPECT_THAT(collectIncludes().includeDepth(MainFile),
|
||||||
UnorderedElementsAre(
|
UnorderedElementsAre(Distance(MainFile, 0u),
|
||||||
Distance(getID(MainFile, Includes), 0u),
|
Distance(testPath("sub/bar.h"), 1u)));
|
||||||
Distance(getID(testPath("sub/bar.h"), Includes), 1u)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HeadersTest, OnlyCollectInclusionsInMain) {
|
TEST_F(HeadersTest, OnlyCollectInclusionsInMain) {
|
||||||
|
@ -179,21 +166,17 @@ TEST_F(HeadersTest, OnlyCollectInclusionsInMain) {
|
||||||
FS.Files[MainFile] = R"cpp(
|
FS.Files[MainFile] = R"cpp(
|
||||||
#include "bar.h"
|
#include "bar.h"
|
||||||
)cpp";
|
)cpp";
|
||||||
auto Includes = collectIncludes();
|
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
collectIncludes().MainFileIncludes,
|
collectIncludes().MainFileIncludes,
|
||||||
UnorderedElementsAre(AllOf(Written("\"bar.h\""), Resolved(BarHeader))));
|
UnorderedElementsAre(AllOf(Written("\"bar.h\""), Resolved(BarHeader))));
|
||||||
EXPECT_THAT(Includes.includeDepth(getID(MainFile, Includes)),
|
EXPECT_THAT(collectIncludes().includeDepth(MainFile),
|
||||||
UnorderedElementsAre(
|
UnorderedElementsAre(Distance(MainFile, 0u),
|
||||||
Distance(getID(MainFile, Includes), 0u),
|
Distance(testPath("sub/bar.h"), 1u),
|
||||||
Distance(getID(testPath("sub/bar.h"), Includes), 1u),
|
Distance(testPath("sub/baz.h"), 2u)));
|
||||||
Distance(getID(testPath("sub/baz.h"), Includes), 2u)));
|
|
||||||
// includeDepth() also works for non-main files.
|
// includeDepth() also works for non-main files.
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(collectIncludes().includeDepth(testPath("sub/bar.h")),
|
||||||
collectIncludes().includeDepth(getID(testPath("sub/bar.h"), Includes)),
|
UnorderedElementsAre(Distance(testPath("sub/bar.h"), 0u),
|
||||||
UnorderedElementsAre(
|
Distance(testPath("sub/baz.h"), 1u)));
|
||||||
Distance(getID(testPath("sub/bar.h"), Includes), 0u),
|
|
||||||
Distance(getID(testPath("sub/baz.h"), Includes), 1u)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HeadersTest, PreambleIncludesPresentOnce) {
|
TEST_F(HeadersTest, PreambleIncludesPresentOnce) {
|
||||||
|
@ -219,32 +202,8 @@ TEST_F(HeadersTest, UnResolvedInclusion) {
|
||||||
|
|
||||||
EXPECT_THAT(collectIncludes().MainFileIncludes,
|
EXPECT_THAT(collectIncludes().MainFileIncludes,
|
||||||
UnorderedElementsAre(AllOf(Written("\"foo.h\""), Resolved(""))));
|
UnorderedElementsAre(AllOf(Written("\"foo.h\""), Resolved(""))));
|
||||||
EXPECT_THAT(collectIncludes().IncludeChildren, IsEmpty());
|
EXPECT_THAT(collectIncludes().includeDepth(MainFile),
|
||||||
}
|
UnorderedElementsAre(Distance(MainFile, 0u)));
|
||||||
|
|
||||||
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) {
|
TEST_F(HeadersTest, IncludeDirective) {
|
||||||
|
|
|
@ -44,11 +44,9 @@ namespace clangd {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using ::testing::AllOf;
|
using ::testing::AllOf;
|
||||||
using ::testing::Contains;
|
|
||||||
using ::testing::ElementsAre;
|
using ::testing::ElementsAre;
|
||||||
using ::testing::ElementsAreArray;
|
using ::testing::ElementsAreArray;
|
||||||
using ::testing::IsEmpty;
|
using ::testing::IsEmpty;
|
||||||
using ::testing::UnorderedElementsAreArray;
|
|
||||||
|
|
||||||
MATCHER_P(DeclNamed, Name, "") {
|
MATCHER_P(DeclNamed, Name, "") {
|
||||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(arg))
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(arg))
|
||||||
|
@ -495,7 +493,7 @@ TEST(ParsedASTTest, PatchesAdditionalIncludes) {
|
||||||
auto EmptyPreamble =
|
auto EmptyPreamble =
|
||||||
buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
|
buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
|
||||||
ASSERT_TRUE(EmptyPreamble);
|
ASSERT_TRUE(EmptyPreamble);
|
||||||
EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, IsEmpty());
|
EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, testing::IsEmpty());
|
||||||
|
|
||||||
// Now build an AST using empty preamble and ensure patched includes worked.
|
// Now build an AST using empty preamble and ensure patched includes worked.
|
||||||
TU.Code = ModifiedContents.str();
|
TU.Code = ModifiedContents.str();
|
||||||
|
@ -509,17 +507,18 @@ TEST(ParsedASTTest, PatchesAdditionalIncludes) {
|
||||||
EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
|
EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
|
||||||
testing::Pointwise(
|
testing::Pointwise(
|
||||||
EqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes));
|
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.
|
// Ensure file proximity signals are correct.
|
||||||
auto &FM = PatchedAST->getSourceManager().getFileManager();
|
EXPECT_EQ(StringMapToVector(PatchedAST->getIncludeStructure().includeDepth(
|
||||||
// Copy so that we can use operator[] to get the children.
|
testPath("foo.cpp"))),
|
||||||
IncludeStructure Includes = PatchedAST->getIncludeStructure();
|
StringMapToVector(ExpectedAST.getIncludeStructure().includeDepth(
|
||||||
auto MainFE = FM.getFile(testPath("foo.cpp"));
|
testPath("foo.cpp"))));
|
||||||
ASSERT_TRUE(MainFE);
|
|
||||||
auto MainID = Includes.getID(*MainFE);
|
|
||||||
auto AuxFE = FM.getFile(testPath("sub/aux.h"));
|
|
||||||
ASSERT_TRUE(AuxFE);
|
|
||||||
auto AuxID = Includes.getID(*AuxFE);
|
|
||||||
EXPECT_THAT(Includes.IncludeChildren[*MainID], Contains(AuxID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ParsedASTTest, PatchesDeletedIncludes) {
|
TEST(ParsedASTTest, PatchesDeletedIncludes) {
|
||||||
|
@ -552,20 +551,18 @@ TEST(ParsedASTTest, PatchesDeletedIncludes) {
|
||||||
EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
|
EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
|
||||||
testing::Pointwise(
|
testing::Pointwise(
|
||||||
EqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes));
|
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.
|
// Ensure file proximity signals are correct.
|
||||||
auto &FM = ExpectedAST.getSourceManager().getFileManager();
|
EXPECT_EQ(StringMapToVector(PatchedAST->getIncludeStructure().includeDepth(
|
||||||
// Copy so that we can getOrCreateID().
|
testPath("foo.cpp"))),
|
||||||
IncludeStructure Includes = ExpectedAST.getIncludeStructure();
|
StringMapToVector(ExpectedAST.getIncludeStructure().includeDepth(
|
||||||
auto MainFE = FM.getFile(testPath("foo.cpp"));
|
testPath("foo.cpp"))));
|
||||||
ASSERT_TRUE(MainFE);
|
|
||||||
auto MainID = Includes.getOrCreateID(*MainFE);
|
|
||||||
auto &PatchedFM = PatchedAST->getSourceManager().getFileManager();
|
|
||||||
IncludeStructure PatchedIncludes = PatchedAST->getIncludeStructure();
|
|
||||||
auto PatchedMainFE = PatchedFM.getFile(testPath("foo.cpp"));
|
|
||||||
ASSERT_TRUE(PatchedMainFE);
|
|
||||||
auto PatchedMainID = PatchedIncludes.getOrCreateID(*PatchedMainFE);
|
|
||||||
EXPECT_EQ(Includes.includeDepth(MainID)[MainID],
|
|
||||||
PatchedIncludes.includeDepth(PatchedMainID)[PatchedMainID]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns Code guarded by #ifndef guards
|
// Returns Code guarded by #ifndef guards
|
||||||
|
|
Loading…
Reference in New Issue