#include "RIFF.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
namespace clang {
namespace clangd {
namespace riff {
-static llvm::Error makeError(const char *Msg) {
- return llvm::createStringError(llvm::inconvertibleErrorCode(), Msg);
+static llvm::Error makeError(const llvm::Twine &Msg) {
+ return llvm::make_error<llvm::StringError>(Msg,
+ llvm::inconvertibleErrorCode());
}
llvm::Expected<Chunk> readChunk(llvm::StringRef &Stream) {
if (Stream.size() < 8)
- return makeError("incomplete chunk header");
+ return makeError("incomplete chunk header: " + llvm::Twine(Stream.size()) +
+ " bytes available");
Chunk C;
std::copy(Stream.begin(), Stream.begin() + 4, C.ID.begin());
Stream = Stream.drop_front(4);
uint32_t Len = llvm::support::endian::read32le(Stream.take_front(4).begin());
Stream = Stream.drop_front(4);
if (Stream.size() < Len)
- return makeError("truncated chunk");
+ return makeError("truncated chunk: want " + llvm::Twine(Len) + ", got " +
+ llvm::Twine(Stream.size()));
C.Data = Stream.take_front(Len);
Stream = Stream.drop_front(Len);
if (Len % 2 & !Stream.empty()) { // Skip padding byte.
if (!RIFF)
return RIFF.takeError();
if (RIFF->ID != fourCC("RIFF"))
- return makeError("not a RIFF container");
+ return makeError("not a RIFF container: root is " + fourCCStr(RIFF->ID));
if (RIFF->Data.size() < 4)
return makeError("RIFF chunk too short");
File F;
inline constexpr FourCC fourCC(const char (&Literal)[5]) {
return FourCC{{Literal[0], Literal[1], Literal[2], Literal[3]}};
}
+inline constexpr llvm::StringRef fourCCStr(const FourCC &Data) {
+ return llvm::StringRef(&Data[0], Data.size());
+}
// A chunk is a section in a RIFF container.
struct Chunk {
FourCC ID;
if (!RIFF)
return RIFF.takeError();
if (RIFF->Type != riff::fourCC("CdIx"))
- return makeError("wrong RIFF type");
+ return makeError("wrong RIFF filetype: " + riff::fourCCStr(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("meta"))
+ return makeError("missing meta chunk");
+ Reader Meta(Chunks.lookup("meta"));
+ auto SeenVersion = Meta.consume32();
+ if (SeenVersion != Version)
+ return makeError("wrong version: want " + llvm::Twine(Version) + ", got " +
+ llvm::Twine(SeenVersion));
+
+ // meta chunk is checked above, as we prefer the "version mismatch" error.
+ for (llvm::StringRef RequiredChunk : {"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();
trace::Span OverallTracer("LoadIndex");
auto Buffer = llvm::MemoryBuffer::getFile(SymbolFilename);
if (!Buffer) {
- elog("Can't open {0}", SymbolFilename);
+ elog("Can't open {0}: {1}", SymbolFilename, Buffer.getError().message());
return nullptr;
}
if (I->Relations)
Relations = std::move(*I->Relations);
} else {
- elog("Bad Index: {0}", I.takeError());
+ elog("Bad index file: {0}", I.takeError());
return nullptr;
}
}