// dependencies. Doesn't own the strings it references (IncludeGraph is
// self-contained).
struct IncludeGraphNode {
- // True if current file is a main file rather than a header.
- bool IsTU = false;
+ enum class SourceFlag : uint8_t {
+ None = 0,
+ // Whether current file is a main file rather than a header.
+ IsTU = 1 << 0,
+ // Whether current file had any uncompilable errors during indexing.
+ HadErrors = 1 << 1,
+ };
+
+ SourceFlag Flags = SourceFlag::None;
llvm::StringRef URI;
FileDigest Digest{{0}};
std::vector<llvm::StringRef> DirectIncludes;
// edges and multi edges.
using IncludeGraph = llvm::StringMap<IncludeGraphNode>;
+inline IncludeGraphNode::SourceFlag operator|(IncludeGraphNode::SourceFlag A,
+ IncludeGraphNode::SourceFlag B) {
+ return static_cast<IncludeGraphNode::SourceFlag>(static_cast<uint8_t>(A) |
+ static_cast<uint8_t>(B));
+}
+
+inline bool operator&(IncludeGraphNode::SourceFlag A,
+ IncludeGraphNode::SourceFlag B) {
+ return static_cast<uint8_t>(A) & static_cast<uint8_t>(B);
+}
+
+inline IncludeGraphNode::SourceFlag &
+operator|=(IncludeGraphNode::SourceFlag &A, IncludeGraphNode::SourceFlag B) {
+ return A = A | B;
+}
+
// Information captured about the inclusion graph in a translation unit.
// This includes detailed information about the direct #includes, and summary
// information about all transitive includes.
// we don't even know what absolute path they should fall in.
// FIXME: Also store contents from other files whenever the current contents
// for those files are missing or if they had errors before.
- if (HadErrors && !IGN.IsTU)
+ if (HadErrors && !(IGN.Flags & IncludeGraphNode::SourceFlag::IsTU))
continue;
const auto AbsPath = URICache.resolve(IGN.URI);
const auto DigestIt = DigestsSnapshot.find(AbsPath);
bool HadErrors = Clang->hasDiagnostics() &&
Clang->getDiagnostics().hasUncompilableErrorOccurred();
+ if (HadErrors) {
+ log("Failed to compile {0}, index may be incomplete", AbsolutePath);
+ for (auto &It : *Index.Sources)
+ It.second.Flags |= IncludeGraphNode::SourceFlag::HadErrors;
+ }
update(AbsolutePath, std::move(Index), DigestsSnapshot, IndexStorage,
HadErrors);
- if (HadErrors)
- log("Failed to compile {0}, index may be incomplete", AbsolutePath);
if (BuildIndexPeriodMs > 0)
SymbolsUpdatedSinceLastIndex = true;
SI.AbsolutePath = CurDependency.Path;
SI.Shard = std::move(Shard);
SI.Digest = I.getValue().Digest;
- SI.CountReferences = I.getValue().IsTU;
+ SI.CountReferences =
+ I.getValue().Flags & IncludeGraphNode::SourceFlag::IsTU;
IntermediateSymbols.push_back(std::move(SI));
// Check if the source needs re-indexing.
// Get the digest, skip it if file doesn't exist.
//===----------------------------------------------------------------------===//
#include "IndexAction.h"
+#include "Headers.h"
#include "Logger.h"
#include "index/Relation.h"
#include "index/SymbolOrigin.h"
}
if (auto Digest = digestFile(SM, FileID))
Node.Digest = std::move(*Digest);
- Node.IsTU = FileID == SM.getMainFileID();
+ if (FileID == SM.getMainFileID())
+ Node.Flags |= IncludeGraphNode::SourceFlag::IsTU;
Node.URI = I->getKey();
}
//===----------------------------------------------------------------------===//
#include "Serialization.h"
+#include "Headers.h"
#include "Logger.h"
#include "RIFF.h"
#include "SymbolLocation.h"
IncludeGraphNode readIncludeGraphNode(Reader &Data,
llvm::ArrayRef<llvm::StringRef> Strings) {
IncludeGraphNode IGN;
- IGN.IsTU = Data.consume8();
+ IGN.Flags = static_cast<IncludeGraphNode::SourceFlag>(Data.consume8());
IGN.URI = Data.consumeString(Strings);
llvm::StringRef Digest = Data.consume(IGN.Digest.size());
std::copy(Digest.bytes_begin(), Digest.bytes_end(), IGN.Digest.begin());
void writeIncludeGraphNode(const IncludeGraphNode &IGN,
const StringTableOut &Strings,
llvm::raw_ostream &OS) {
- OS.write(IGN.IsTU);
+ OS.write(static_cast<uint8_t>(IGN.Flags));
writeVar(Strings.index(IGN.URI), OS);
llvm::StringRef Hash(reinterpret_cast<const char *>(IGN.Digest.data()),
IGN.Digest.size());
// The current versioning scheme is simple - non-current versions are rejected.
// If you make a breaking change, bump this version number to invalidate stored
// data. Later we may want to support some backward compatibility.
-constexpr static uint32_t Version = 10;
+constexpr static uint32_t Version = 11;
llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) {
auto RIFF = riff::readFile(Data);
+#include "Headers.h"
#include "SyncAPI.h"
#include "TestFS.h"
#include "TestTU.h"
}
// URI cannot be empty since it references keys in the IncludeGraph.
MATCHER(EmptyIncludeNode, "") {
- return !arg.IsTU && !arg.URI.empty() && arg.Digest == FileDigest{{0}} &&
- arg.DirectIncludes.empty();
+ return arg.Flags == IncludeGraphNode::SourceFlag::None && !arg.URI.empty() &&
+ arg.Digest == FileDigest{{0}} && arg.DirectIncludes.empty();
}
+
+MATCHER(HadErrors, "") {
+ return arg.Flags & IncludeGraphNode::SourceFlag::HadErrors;
+}
+
MATCHER_P(NumReferences, N, "") { return arg.References == N; }
class MemoryShardStorage : public BackgroundIndexStorage {
EXPECT_THAT(Shard->Sources->keys(),
UnorderedElementsAre("unittest:///A.cc", "unittest:///A.h",
"unittest:///B.h"));
+
+ EXPECT_THAT(Shard->Sources->lookup("unittest:///A.cc"), HadErrors());
+ // FIXME: We should also persist headers while marking them with errors.
+ EXPECT_THAT(Shard->Sources->lookup("unittest:///A.h"), Not(HadErrors()));
+ EXPECT_THAT(Shard->Sources->lookup("unittest:///B.h"), Not(HadErrors()));
}
TEST_F(BackgroundIndexTest, CmdLineHash) {
//
//===----------------------------------------------------------------------===//
+#include "Headers.h"
#include "TestFS.h"
#include "index/IndexAction.h"
#include "clang/Tooling/Tooling.h"
std::string toUri(llvm::StringRef Path) { return URI::create(Path).toString(); }
-MATCHER(IsTU, "") { return arg.IsTU; }
+MATCHER(IsTU, "") { return arg.Flags & IncludeGraphNode::SourceFlag::IsTU; }
MATCHER_P(HasDigest, Digest, "") { return arg.Digest == Digest; }
//
//===----------------------------------------------------------------------===//
+#include "Headers.h"
#include "index/Index.h"
#include "index/Serialization.h"
#include "clang/Tooling/CompilationDatabase.h"
TestContent.size()});
IGN.DirectIncludes = {"inc1", "inc2"};
IGN.URI = "URI";
- IGN.IsTU = true;
+ IGN.Flags |= IncludeGraphNode::SourceFlag::IsTU;
+ IGN.Flags |= IncludeGraphNode::SourceFlag::HadErrors;
IncludeGraph Sources;
Sources[IGN.URI] = IGN;
// Write to binary format, and parse again.
EXPECT_EQ(IGNDeserialized.Digest, IGN.Digest);
EXPECT_EQ(IGNDeserialized.DirectIncludes, IGN.DirectIncludes);
EXPECT_EQ(IGNDeserialized.URI, IGN.URI);
- EXPECT_EQ(IGNDeserialized.IsTU, IGN.IsTU);
+ EXPECT_EQ(IGNDeserialized.Flags, IGN.Flags);
}
}