| //===--  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(const Record &R, llvm::SmallVectorImpl<char> &Field, | 
 |                          llvm::StringRef Blob) { | 
 |   Field.assign(Blob.begin(), Blob.end()); | 
 |   return llvm::Error::success(); | 
 | } | 
 |  | 
 | llvm::Error decodeRecord(const 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(const Record &R, bool &Field, llvm::StringRef Blob) { | 
 |   Field = R[0] != 0; | 
 |   return llvm::Error::success(); | 
 | } | 
 |  | 
 | llvm::Error decodeRecord(const 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(const 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(const 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(const 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(const 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(const 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(const Record &R, | 
 |                          llvm::SmallVectorImpl<llvm::SmallString<16>> &Field, | 
 |                          llvm::StringRef Blob) { | 
 |   Field.push_back(Blob); | 
 |   return llvm::Error::success(); | 
 | } | 
 |  | 
 | llvm::Error decodeRecord(const 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(const 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(const 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(const 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(const 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(const 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(const 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(const Record &R, unsigned ID, llvm::StringRef Blob, | 
 |                         TypeInfo *I) { | 
 |   return llvm::Error::success(); | 
 | } | 
 |  | 
 | llvm::Error parseRecord(const 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(const 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(const 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(const 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 |