forked from OSchip/llvm-project
773 lines
24 KiB
C++
773 lines
24 KiB
C++
//===-- BitcodeReader.cpp - ClangDoc Bitcode Reader ------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "BitcodeReader.h"
|
|
#include "llvm/ADT/IndexedMap.h"
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace clang {
|
|
namespace doc {
|
|
|
|
using Record = llvm::SmallVector<uint64_t, 1024>;
|
|
|
|
llvm::Error decodeRecord(Record R, llvm::SmallVectorImpl<char> &Field,
|
|
llvm::StringRef Blob) {
|
|
Field.assign(Blob.begin(), Blob.end());
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) {
|
|
if (R[0] != BitCodeConstants::USRHashSize)
|
|
return llvm::make_error<llvm::StringError>("Incorrect USR size.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
|
|
// First position in the record is the length of the following array, so we
|
|
// copy the following elements to the field.
|
|
for (int I = 0, E = R[0]; I < E; ++I)
|
|
Field[I] = R[I + 1];
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, bool &Field, llvm::StringRef Blob) {
|
|
Field = R[0] != 0;
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, int &Field, llvm::StringRef Blob) {
|
|
if (R[0] > INT_MAX)
|
|
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
Field = (int)R[0];
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, AccessSpecifier &Field,
|
|
llvm::StringRef Blob) {
|
|
switch (R[0]) {
|
|
case AS_public:
|
|
case AS_private:
|
|
case AS_protected:
|
|
case AS_none:
|
|
Field = (AccessSpecifier)R[0];
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid value for AccessSpecifier.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) {
|
|
switch (R[0]) {
|
|
case TTK_Struct:
|
|
case TTK_Interface:
|
|
case TTK_Union:
|
|
case TTK_Class:
|
|
case TTK_Enum:
|
|
Field = (TagTypeKind)R[0];
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid value for TagTypeKind.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, llvm::Optional<Location> &Field,
|
|
llvm::StringRef Blob) {
|
|
if (R[0] > INT_MAX)
|
|
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
Field.emplace((int)R[0], Blob);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) {
|
|
switch (auto IT = static_cast<InfoType>(R[0])) {
|
|
case InfoType::IT_namespace:
|
|
case InfoType::IT_record:
|
|
case InfoType::IT_function:
|
|
case InfoType::IT_default:
|
|
case InfoType::IT_enum:
|
|
Field = IT;
|
|
return llvm::Error::success();
|
|
}
|
|
return llvm::make_error<llvm::StringError>("Invalid value for InfoType.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) {
|
|
switch (auto F = static_cast<FieldId>(R[0])) {
|
|
case FieldId::F_namespace:
|
|
case FieldId::F_parent:
|
|
case FieldId::F_vparent:
|
|
case FieldId::F_type:
|
|
case FieldId::F_child_namespace:
|
|
case FieldId::F_child_record:
|
|
case FieldId::F_default:
|
|
Field = F;
|
|
return llvm::Error::success();
|
|
}
|
|
return llvm::make_error<llvm::StringError>("Invalid value for FieldId.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R,
|
|
llvm::SmallVectorImpl<llvm::SmallString<16>> &Field,
|
|
llvm::StringRef Blob) {
|
|
Field.push_back(Blob);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error decodeRecord(Record R, llvm::SmallVectorImpl<Location> &Field,
|
|
llvm::StringRef Blob) {
|
|
if (R[0] > INT_MAX)
|
|
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
Field.emplace_back((int)R[0], Blob);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
const unsigned VersionNo) {
|
|
if (ID == VERSION && R[0] == VersionNo)
|
|
return llvm::Error::success();
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Mismatched bitcode version number.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
NamespaceInfo *I) {
|
|
switch (ID) {
|
|
case NAMESPACE_USR:
|
|
return decodeRecord(R, I->USR, Blob);
|
|
case NAMESPACE_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
case NAMESPACE_PATH:
|
|
return decodeRecord(R, I->Path, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
RecordInfo *I) {
|
|
switch (ID) {
|
|
case RECORD_USR:
|
|
return decodeRecord(R, I->USR, Blob);
|
|
case RECORD_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
case RECORD_PATH:
|
|
return decodeRecord(R, I->Path, Blob);
|
|
case RECORD_DEFLOCATION:
|
|
return decodeRecord(R, I->DefLoc, Blob);
|
|
case RECORD_LOCATION:
|
|
return decodeRecord(R, I->Loc, Blob);
|
|
case RECORD_TAG_TYPE:
|
|
return decodeRecord(R, I->TagType, Blob);
|
|
case RECORD_IS_TYPE_DEF:
|
|
return decodeRecord(R, I->IsTypeDef, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid field for RecordInfo.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
EnumInfo *I) {
|
|
switch (ID) {
|
|
case ENUM_USR:
|
|
return decodeRecord(R, I->USR, Blob);
|
|
case ENUM_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
case ENUM_DEFLOCATION:
|
|
return decodeRecord(R, I->DefLoc, Blob);
|
|
case ENUM_LOCATION:
|
|
return decodeRecord(R, I->Loc, Blob);
|
|
case ENUM_MEMBER:
|
|
return decodeRecord(R, I->Members, Blob);
|
|
case ENUM_SCOPED:
|
|
return decodeRecord(R, I->Scoped, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>("Invalid field for EnumInfo.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
FunctionInfo *I) {
|
|
switch (ID) {
|
|
case FUNCTION_USR:
|
|
return decodeRecord(R, I->USR, Blob);
|
|
case FUNCTION_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
case FUNCTION_DEFLOCATION:
|
|
return decodeRecord(R, I->DefLoc, Blob);
|
|
case FUNCTION_LOCATION:
|
|
return decodeRecord(R, I->Loc, Blob);
|
|
case FUNCTION_ACCESS:
|
|
return decodeRecord(R, I->Access, Blob);
|
|
case FUNCTION_IS_METHOD:
|
|
return decodeRecord(R, I->IsMethod, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid field for FunctionInfo.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
TypeInfo *I) {
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
FieldTypeInfo *I) {
|
|
switch (ID) {
|
|
case FIELD_TYPE_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>("Invalid field for TypeInfo.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
MemberTypeInfo *I) {
|
|
switch (ID) {
|
|
case MEMBER_TYPE_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
case MEMBER_TYPE_ACCESS:
|
|
return decodeRecord(R, I->Access, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid field for MemberTypeInfo.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
CommentInfo *I) {
|
|
switch (ID) {
|
|
case COMMENT_KIND:
|
|
return decodeRecord(R, I->Kind, Blob);
|
|
case COMMENT_TEXT:
|
|
return decodeRecord(R, I->Text, Blob);
|
|
case COMMENT_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
case COMMENT_DIRECTION:
|
|
return decodeRecord(R, I->Direction, Blob);
|
|
case COMMENT_PARAMNAME:
|
|
return decodeRecord(R, I->ParamName, Blob);
|
|
case COMMENT_CLOSENAME:
|
|
return decodeRecord(R, I->CloseName, Blob);
|
|
case COMMENT_ATTRKEY:
|
|
return decodeRecord(R, I->AttrKeys, Blob);
|
|
case COMMENT_ATTRVAL:
|
|
return decodeRecord(R, I->AttrValues, Blob);
|
|
case COMMENT_ARG:
|
|
return decodeRecord(R, I->Args, Blob);
|
|
case COMMENT_SELFCLOSING:
|
|
return decodeRecord(R, I->SelfClosing, Blob);
|
|
case COMMENT_EXPLICIT:
|
|
return decodeRecord(R, I->Explicit, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid field for CommentInfo.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
|
Reference *I, FieldId &F) {
|
|
switch (ID) {
|
|
case REFERENCE_USR:
|
|
return decodeRecord(R, I->USR, Blob);
|
|
case REFERENCE_NAME:
|
|
return decodeRecord(R, I->Name, Blob);
|
|
case REFERENCE_TYPE:
|
|
return decodeRecord(R, I->RefType, Blob);
|
|
case REFERENCE_PATH:
|
|
return decodeRecord(R, I->Path, Blob);
|
|
case REFERENCE_FIELD:
|
|
return decodeRecord(R, F, Blob);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>("Invalid field for Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <typename T> llvm::Expected<CommentInfo *> getCommentInfo(T I) {
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain CommentInfo.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
|
|
template <> llvm::Expected<CommentInfo *> getCommentInfo(FunctionInfo *I) {
|
|
I->Description.emplace_back();
|
|
return &I->Description.back();
|
|
}
|
|
|
|
template <> llvm::Expected<CommentInfo *> getCommentInfo(NamespaceInfo *I) {
|
|
I->Description.emplace_back();
|
|
return &I->Description.back();
|
|
}
|
|
|
|
template <> llvm::Expected<CommentInfo *> getCommentInfo(RecordInfo *I) {
|
|
I->Description.emplace_back();
|
|
return &I->Description.back();
|
|
}
|
|
|
|
template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumInfo *I) {
|
|
I->Description.emplace_back();
|
|
return &I->Description.back();
|
|
}
|
|
|
|
template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
|
|
I->Children.emplace_back(llvm::make_unique<CommentInfo>());
|
|
return I->Children.back().get();
|
|
}
|
|
|
|
template <>
|
|
llvm::Expected<CommentInfo *> getCommentInfo(std::unique_ptr<CommentInfo> &I) {
|
|
return getCommentInfo(I.get());
|
|
}
|
|
|
|
template <typename T, typename TTypeInfo>
|
|
llvm::Error addTypeInfo(T I, TTypeInfo &&TI) {
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain TypeInfo.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
|
|
template <> llvm::Error addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) {
|
|
I->Members.emplace_back(std::move(T));
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
template <> llvm::Error addTypeInfo(FunctionInfo *I, TypeInfo &&T) {
|
|
I->ReturnType = std::move(T);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
template <> llvm::Error addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) {
|
|
I->Params.emplace_back(std::move(T));
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
template <typename T> llvm::Error addReference(T I, Reference &&R, FieldId F) {
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
|
|
template <> llvm::Error addReference(TypeInfo *I, Reference &&R, FieldId F) {
|
|
switch (F) {
|
|
case FieldId::F_type:
|
|
I->Type = std::move(R);
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <>
|
|
llvm::Error addReference(FieldTypeInfo *I, Reference &&R, FieldId F) {
|
|
switch (F) {
|
|
case FieldId::F_type:
|
|
I->Type = std::move(R);
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <>
|
|
llvm::Error addReference(MemberTypeInfo *I, Reference &&R, FieldId F) {
|
|
switch (F) {
|
|
case FieldId::F_type:
|
|
I->Type = std::move(R);
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <> llvm::Error addReference(EnumInfo *I, Reference &&R, FieldId F) {
|
|
switch (F) {
|
|
case FieldId::F_namespace:
|
|
I->Namespace.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <>
|
|
llvm::Error addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
|
|
switch (F) {
|
|
case FieldId::F_namespace:
|
|
I->Namespace.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
case FieldId::F_child_namespace:
|
|
I->ChildNamespaces.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
case FieldId::F_child_record:
|
|
I->ChildRecords.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <>
|
|
llvm::Error addReference(FunctionInfo *I, Reference &&R, FieldId F) {
|
|
switch (F) {
|
|
case FieldId::F_namespace:
|
|
I->Namespace.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
case FieldId::F_parent:
|
|
I->Parent = std::move(R);
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F) {
|
|
switch (F) {
|
|
case FieldId::F_namespace:
|
|
I->Namespace.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
case FieldId::F_parent:
|
|
I->Parents.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
case FieldId::F_vparent:
|
|
I->VirtualParents.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
case FieldId::F_child_record:
|
|
I->ChildRecords.emplace_back(std::move(R));
|
|
return llvm::Error::success();
|
|
default:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid type cannot contain Reference.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
template <typename T, typename ChildInfoType>
|
|
void addChild(T I, ChildInfoType &&R) {
|
|
llvm::errs() << "Invalid child type for info.\n";
|
|
exit(1);
|
|
}
|
|
|
|
template <> void addChild(NamespaceInfo *I, FunctionInfo &&R) {
|
|
I->ChildFunctions.emplace_back(std::move(R));
|
|
}
|
|
|
|
template <> void addChild(NamespaceInfo *I, EnumInfo &&R) {
|
|
I->ChildEnums.emplace_back(std::move(R));
|
|
}
|
|
|
|
template <> void addChild(RecordInfo *I, FunctionInfo &&R) {
|
|
I->ChildFunctions.emplace_back(std::move(R));
|
|
}
|
|
|
|
template <> void addChild(RecordInfo *I, EnumInfo &&R) {
|
|
I->ChildEnums.emplace_back(std::move(R));
|
|
}
|
|
|
|
// Read records from bitcode into a given info.
|
|
template <typename T>
|
|
llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
|
|
Record R;
|
|
llvm::StringRef Blob;
|
|
llvm::Expected<unsigned> MaybeRecID = Stream.readRecord(ID, R, &Blob);
|
|
if (!MaybeRecID)
|
|
return MaybeRecID.takeError();
|
|
return parseRecord(R, MaybeRecID.get(), Blob, I);
|
|
}
|
|
|
|
template <>
|
|
llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) {
|
|
Record R;
|
|
llvm::StringRef Blob;
|
|
llvm::Expected<unsigned> MaybeRecID = Stream.readRecord(ID, R, &Blob);
|
|
if (!MaybeRecID)
|
|
return MaybeRecID.takeError();
|
|
return parseRecord(R, MaybeRecID.get(), Blob, I, CurrentReferenceField);
|
|
}
|
|
|
|
// Read a block of records into a single info.
|
|
template <typename T>
|
|
llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
|
|
if (llvm::Error Err = Stream.EnterSubBlock(ID))
|
|
return Err;
|
|
|
|
while (true) {
|
|
unsigned BlockOrCode = 0;
|
|
Cursor Res = skipUntilRecordOrBlock(BlockOrCode);
|
|
|
|
switch (Res) {
|
|
case Cursor::BadBlock:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Bad block found.\n", llvm::inconvertibleErrorCode());
|
|
case Cursor::BlockEnd:
|
|
return llvm::Error::success();
|
|
case Cursor::BlockBegin:
|
|
if (llvm::Error Err = readSubBlock(BlockOrCode, I)) {
|
|
if (llvm::Error Skipped = Stream.SkipBlock())
|
|
return joinErrors(std::move(Err), std::move(Skipped));
|
|
return Err;
|
|
}
|
|
continue;
|
|
case Cursor::Record:
|
|
break;
|
|
}
|
|
if (auto Err = readRecord(BlockOrCode, I))
|
|
return Err;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
|
|
switch (ID) {
|
|
// Blocks can only have Comment, Reference, TypeInfo, FunctionInfo, or
|
|
// EnumInfo subblocks
|
|
case BI_COMMENT_BLOCK_ID: {
|
|
auto Comment = getCommentInfo(I);
|
|
if (!Comment)
|
|
return Comment.takeError();
|
|
if (auto Err = readBlock(ID, Comment.get()))
|
|
return Err;
|
|
return llvm::Error::success();
|
|
}
|
|
case BI_TYPE_BLOCK_ID: {
|
|
TypeInfo TI;
|
|
if (auto Err = readBlock(ID, &TI))
|
|
return Err;
|
|
if (auto Err = addTypeInfo(I, std::move(TI)))
|
|
return Err;
|
|
return llvm::Error::success();
|
|
}
|
|
case BI_FIELD_TYPE_BLOCK_ID: {
|
|
FieldTypeInfo TI;
|
|
if (auto Err = readBlock(ID, &TI))
|
|
return Err;
|
|
if (auto Err = addTypeInfo(I, std::move(TI)))
|
|
return Err;
|
|
return llvm::Error::success();
|
|
}
|
|
case BI_MEMBER_TYPE_BLOCK_ID: {
|
|
MemberTypeInfo TI;
|
|
if (auto Err = readBlock(ID, &TI))
|
|
return Err;
|
|
if (auto Err = addTypeInfo(I, std::move(TI)))
|
|
return Err;
|
|
return llvm::Error::success();
|
|
}
|
|
case BI_REFERENCE_BLOCK_ID: {
|
|
Reference R;
|
|
if (auto Err = readBlock(ID, &R))
|
|
return Err;
|
|
if (auto Err = addReference(I, std::move(R), CurrentReferenceField))
|
|
return Err;
|
|
return llvm::Error::success();
|
|
}
|
|
case BI_FUNCTION_BLOCK_ID: {
|
|
FunctionInfo F;
|
|
if (auto Err = readBlock(ID, &F))
|
|
return Err;
|
|
addChild(I, std::move(F));
|
|
return llvm::Error::success();
|
|
}
|
|
case BI_ENUM_BLOCK_ID: {
|
|
EnumInfo E;
|
|
if (auto Err = readBlock(ID, &E))
|
|
return Err;
|
|
addChild(I, std::move(E));
|
|
return llvm::Error::success();
|
|
}
|
|
default:
|
|
return llvm::make_error<llvm::StringError>("Invalid subblock type.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
ClangDocBitcodeReader::Cursor
|
|
ClangDocBitcodeReader::skipUntilRecordOrBlock(unsigned &BlockOrRecordID) {
|
|
BlockOrRecordID = 0;
|
|
|
|
while (!Stream.AtEndOfStream()) {
|
|
Expected<unsigned> MaybeCode = Stream.ReadCode();
|
|
if (!MaybeCode) {
|
|
// FIXME this drops the error on the floor.
|
|
consumeError(MaybeCode.takeError());
|
|
return Cursor::BadBlock;
|
|
}
|
|
|
|
unsigned Code = MaybeCode.get();
|
|
if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {
|
|
BlockOrRecordID = Code;
|
|
return Cursor::Record;
|
|
}
|
|
switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {
|
|
case llvm::bitc::ENTER_SUBBLOCK:
|
|
if (Expected<unsigned> MaybeID = Stream.ReadSubBlockID())
|
|
BlockOrRecordID = MaybeID.get();
|
|
else {
|
|
// FIXME this drops the error on the floor.
|
|
consumeError(MaybeID.takeError());
|
|
}
|
|
return Cursor::BlockBegin;
|
|
case llvm::bitc::END_BLOCK:
|
|
if (Stream.ReadBlockEnd())
|
|
return Cursor::BadBlock;
|
|
return Cursor::BlockEnd;
|
|
case llvm::bitc::DEFINE_ABBREV:
|
|
if (llvm::Error Err = Stream.ReadAbbrevRecord()) {
|
|
// FIXME this drops the error on the floor.
|
|
consumeError(std::move(Err));
|
|
}
|
|
continue;
|
|
case llvm::bitc::UNABBREV_RECORD:
|
|
return Cursor::BadBlock;
|
|
case llvm::bitc::FIRST_APPLICATION_ABBREV:
|
|
llvm_unreachable("Unexpected abbrev id.");
|
|
}
|
|
}
|
|
llvm_unreachable("Premature stream end.");
|
|
}
|
|
|
|
llvm::Error ClangDocBitcodeReader::validateStream() {
|
|
if (Stream.AtEndOfStream())
|
|
return llvm::make_error<llvm::StringError>("Premature end of stream.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
|
|
// Sniff for the signature.
|
|
for (int Idx = 0; Idx != 4; ++Idx) {
|
|
Expected<llvm::SimpleBitstreamCursor::word_t> MaybeRead = Stream.Read(8);
|
|
if (!MaybeRead)
|
|
return MaybeRead.takeError();
|
|
else if (MaybeRead.get() != BitCodeConstants::Signature[Idx])
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid bitcode signature.\n", llvm::inconvertibleErrorCode());
|
|
}
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error ClangDocBitcodeReader::readBlockInfoBlock() {
|
|
Expected<Optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
|
|
Stream.ReadBlockInfoBlock();
|
|
if (!MaybeBlockInfo)
|
|
return MaybeBlockInfo.takeError();
|
|
else
|
|
BlockInfo = MaybeBlockInfo.get();
|
|
if (!BlockInfo)
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Unable to parse BlockInfoBlock.\n", llvm::inconvertibleErrorCode());
|
|
Stream.setBlockInfo(&*BlockInfo);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
template <typename T>
|
|
llvm::Expected<std::unique_ptr<Info>>
|
|
ClangDocBitcodeReader::createInfo(unsigned ID) {
|
|
std::unique_ptr<Info> I = llvm::make_unique<T>();
|
|
if (auto Err = readBlock(ID, static_cast<T *>(I.get())))
|
|
return std::move(Err);
|
|
return std::unique_ptr<Info>{std::move(I)};
|
|
}
|
|
|
|
llvm::Expected<std::unique_ptr<Info>>
|
|
ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
|
|
switch (ID) {
|
|
case BI_NAMESPACE_BLOCK_ID:
|
|
return createInfo<NamespaceInfo>(ID);
|
|
case BI_RECORD_BLOCK_ID:
|
|
return createInfo<RecordInfo>(ID);
|
|
case BI_ENUM_BLOCK_ID:
|
|
return createInfo<EnumInfo>(ID);
|
|
case BI_FUNCTION_BLOCK_ID:
|
|
return createInfo<FunctionInfo>(ID);
|
|
default:
|
|
return llvm::make_error<llvm::StringError>("Cannot create info.\n",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|
|
}
|
|
|
|
// Entry point
|
|
llvm::Expected<std::vector<std::unique_ptr<Info>>>
|
|
ClangDocBitcodeReader::readBitcode() {
|
|
std::vector<std::unique_ptr<Info>> Infos;
|
|
if (auto Err = validateStream())
|
|
return std::move(Err);
|
|
|
|
// Read the top level blocks.
|
|
while (!Stream.AtEndOfStream()) {
|
|
Expected<unsigned> MaybeCode = Stream.ReadCode();
|
|
if (!MaybeCode)
|
|
return MaybeCode.takeError();
|
|
if (MaybeCode.get() != llvm::bitc::ENTER_SUBBLOCK)
|
|
return llvm::make_error<llvm::StringError>(
|
|
"No blocks in input.\n", llvm::inconvertibleErrorCode());
|
|
Expected<unsigned> MaybeID = Stream.ReadSubBlockID();
|
|
if (!MaybeID)
|
|
return MaybeID.takeError();
|
|
unsigned ID = MaybeID.get();
|
|
switch (ID) {
|
|
// NamedType and Comment blocks should not appear at the top level
|
|
case BI_TYPE_BLOCK_ID:
|
|
case BI_FIELD_TYPE_BLOCK_ID:
|
|
case BI_MEMBER_TYPE_BLOCK_ID:
|
|
case BI_COMMENT_BLOCK_ID:
|
|
case BI_REFERENCE_BLOCK_ID:
|
|
return llvm::make_error<llvm::StringError>(
|
|
"Invalid top level block.\n", llvm::inconvertibleErrorCode());
|
|
case BI_NAMESPACE_BLOCK_ID:
|
|
case BI_RECORD_BLOCK_ID:
|
|
case BI_ENUM_BLOCK_ID:
|
|
case BI_FUNCTION_BLOCK_ID: {
|
|
auto InfoOrErr = readBlockToInfo(ID);
|
|
if (!InfoOrErr)
|
|
return InfoOrErr.takeError();
|
|
Infos.emplace_back(std::move(InfoOrErr.get()));
|
|
continue;
|
|
}
|
|
case BI_VERSION_BLOCK_ID:
|
|
if (auto Err = readBlock(ID, VersionNumber))
|
|
return std::move(Err);
|
|
continue;
|
|
case llvm::bitc::BLOCKINFO_BLOCK_ID:
|
|
if (auto Err = readBlockInfoBlock())
|
|
return std::move(Err);
|
|
continue;
|
|
default:
|
|
if (llvm::Error Err = Stream.SkipBlock()) {
|
|
// FIXME this drops the error on the floor.
|
|
consumeError(std::move(Err));
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
return std::move(Infos);
|
|
}
|
|
|
|
} // namespace doc
|
|
} // namespace clang
|