Mercurial > hg > CbC > CbC_llvm
diff clang-tools-extra/clang-doc/BitcodeReader.cpp @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children | c4bab56944e8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp Thu Feb 13 15:10:13 2020 +0900 @@ -0,0 +1,807 @@ +//===-- 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::createStringError(llvm::inconvertibleErrorCode(), + "incorrect USR size"); + + // 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::createStringError(llvm::inconvertibleErrorCode(), + "integer too large to parse"); + 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::createStringError(llvm::inconvertibleErrorCode(), + "invalid value for AccessSpecifier"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid value for TagTypeKind"); + } +} + +llvm::Error decodeRecord(Record R, llvm::Optional<Location> &Field, + llvm::StringRef Blob) { + if (R[0] > INT_MAX) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "integer too large to parse"); + Field.emplace((int)R[0], Blob, (bool)R[1]); + 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::createStringError(llvm::inconvertibleErrorCode(), + "invalid value for InfoType"); +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid value for FieldId"); +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "integer too large to parse"); + Field.emplace_back((int)R[0], Blob, (bool)R[1]); + 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::createStringError(llvm::inconvertibleErrorCode(), + "mismatched bitcode version number"); +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for NamespaceInfo"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for RecordInfo"); + } +} + +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + BaseRecordInfo *I) { + switch (ID) { + case BASE_RECORD_USR: + return decodeRecord(R, I->USR, Blob); + case BASE_RECORD_NAME: + return decodeRecord(R, I->Name, Blob); + case BASE_RECORD_PATH: + return decodeRecord(R, I->Path, Blob); + case BASE_RECORD_TAG_TYPE: + return decodeRecord(R, I->TagType, Blob); + case BASE_RECORD_IS_VIRTUAL: + return decodeRecord(R, I->IsVirtual, Blob); + case BASE_RECORD_ACCESS: + return decodeRecord(R, I->Access, Blob); + case BASE_RECORD_IS_PARENT: + return decodeRecord(R, I->IsParent, Blob); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for BaseRecordInfo"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for EnumInfo"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for FunctionInfo"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for TypeInfo"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for MemberTypeInfo"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for CommentInfo"); + } +} + +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_IS_IN_GLOBAL_NAMESPACE: + return decodeRecord(R, I->IsInGlobalNamespace, Blob); + case REFERENCE_FIELD: + return decodeRecord(R, F, Blob); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for Reference"); + } +} + +template <typename T> llvm::Expected<CommentInfo *> getCommentInfo(T I) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain CommentInfo"); +} + +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(std::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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain TypeInfo"); +} + +template <> llvm::Error addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) { + I->Members.emplace_back(std::move(T)); + return llvm::Error::success(); +} + +template <> llvm::Error addTypeInfo(BaseRecordInfo *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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "invalid type cannot contain Reference"); + } +} + +template <typename T, typename ChildInfoType> +void addChild(T I, ChildInfoType &&R) { + llvm::errs() << "invalid child type for info"; + 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)); +} + +template <> void addChild(RecordInfo *I, BaseRecordInfo &&R) { + I->Bases.emplace_back(std::move(R)); +} + +template <> void addChild(BaseRecordInfo *I, FunctionInfo &&R) { + I->ChildFunctions.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::createStringError(llvm::inconvertibleErrorCode(), + "bad block found"); + 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_BASE_RECORD_BLOCK_ID: { + BaseRecordInfo BR; + if (auto Err = readBlock(ID, &BR)) + return Err; + addChild(I, std::move(BR)); + 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::createStringError(llvm::inconvertibleErrorCode(), + "invalid subblock type"); + } +} + +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::createStringError(llvm::inconvertibleErrorCode(), + "premature end of stream"); + + // 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::createStringError(llvm::inconvertibleErrorCode(), + "invalid bitcode signature"); + } + 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::createStringError(llvm::inconvertibleErrorCode(), + "unable to parse BlockInfoBlock"); + 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 = std::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::createStringError(llvm::inconvertibleErrorCode(), + "cannot create info"); + } +} + +// 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::createStringError(llvm::inconvertibleErrorCode(), + "no blocks in input"); + 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::createStringError(llvm::inconvertibleErrorCode(), + "invalid top level block"); + 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