//===-- 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/Support/Error.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include namespace clang { namespace doc { using Record = llvm::SmallVector; // This implements decode for SmallString. static llvm::Error decodeRecord(const Record &R, llvm::SmallVectorImpl &Field, llvm::StringRef Blob) { Field.assign(Blob.begin(), Blob.end()); return llvm::Error::success(); } static 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(); } static llvm::Error decodeRecord(const Record &R, bool &Field, llvm::StringRef Blob) { Field = R[0] != 0; return llvm::Error::success(); } static 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(); } llvm_unreachable("invalid value for AccessSpecifier"); } static llvm::Error decodeRecord(const Record &R, TagTypeKind &Field, llvm::StringRef Blob) { switch (static_cast(R[0])) { case TagTypeKind::Struct: case TagTypeKind::Interface: case TagTypeKind::Union: case TagTypeKind::Class: case TagTypeKind::Enum: Field = static_cast(R[0]); return llvm::Error::success(); } return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid value for TagTypeKind"); } static llvm::Error decodeRecord(const Record &R, std::optional &Field, llvm::StringRef Blob) { if (R[0] > INT_MAX) return llvm::createStringError(llvm::inconvertibleErrorCode(), "integer too large to parse"); Field.emplace(static_cast(R[0]), static_cast(R[1]), Blob, static_cast(R[2])); return llvm::Error::success(); } static llvm::Error decodeRecord(const Record &R, InfoType &Field, llvm::StringRef Blob) { switch (auto IT = static_cast(R[0])) { case InfoType::IT_namespace: case InfoType::IT_record: case InfoType::IT_function: case InfoType::IT_default: case InfoType::IT_enum: case InfoType::IT_typedef: case InfoType::IT_concept: case InfoType::IT_variable: case InfoType::IT_friend: Field = IT; return llvm::Error::success(); } return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid value for InfoType"); } static llvm::Error decodeRecord(const Record &R, FieldId &Field, llvm::StringRef Blob) { switch (auto F = static_cast(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_concept: case FieldId::F_friend: case FieldId::F_default: Field = F; return llvm::Error::success(); } return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid value for FieldId"); } static llvm::Error decodeRecord(const Record &R, llvm::SmallVectorImpl> &Field, llvm::StringRef Blob) { Field.push_back(Blob); return llvm::Error::success(); } static llvm::Error decodeRecord(const Record &R, llvm::SmallVectorImpl &Field, llvm::StringRef Blob) { if (R[0] > INT_MAX) return llvm::createStringError(llvm::inconvertibleErrorCode(), "integer too large to parse"); Field.emplace_back(static_cast(R[0]), static_cast(R[1]), Blob, static_cast(R[2])); return llvm::Error::success(); } static 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"); } static 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"); } } static 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); case RECORD_MANGLED_NAME: return decodeRecord(R, I->MangledName, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for RecordInfo"); } } static 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"); } } static 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_SCOPED: return decodeRecord(R, I->Scoped, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for EnumInfo"); } } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, TypedefInfo *I) { switch (ID) { case TYPEDEF_USR: return decodeRecord(R, I->USR, Blob); case TYPEDEF_NAME: return decodeRecord(R, I->Name, Blob); case TYPEDEF_DEFLOCATION: return decodeRecord(R, I->DefLoc, Blob); case TYPEDEF_IS_USING: return decodeRecord(R, I->IsUsing, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for TypedefInfo"); } } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, EnumValueInfo *I) { switch (ID) { case ENUM_VALUE_NAME: return decodeRecord(R, I->Name, Blob); case ENUM_VALUE_VALUE: return decodeRecord(R, I->Value, Blob); case ENUM_VALUE_EXPR: return decodeRecord(R, I->ValueExpr, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for EnumValueInfo"); } } static 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); case FUNCTION_IS_STATIC: return decodeRecord(R, I->IsStatic, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for FunctionInfo"); } } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, TypeInfo *I) { switch (ID) { case TYPE_IS_BUILTIN: return decodeRecord(R, I->IsBuiltIn, Blob); case TYPE_IS_TEMPLATE: return decodeRecord(R, I->IsTemplate, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for TypeInfo"); } } static 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); case FIELD_DEFAULT_VALUE: return decodeRecord(R, I->DefaultValue, Blob); case FIELD_TYPE_IS_BUILTIN: return decodeRecord(R, I->IsBuiltIn, Blob); case FIELD_TYPE_IS_TEMPLATE: return decodeRecord(R, I->IsTemplate, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for TypeInfo"); } } static 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); case MEMBER_TYPE_IS_STATIC: return decodeRecord(R, I->IsStatic, Blob); case MEMBER_TYPE_IS_BUILTIN: return decodeRecord(R, I->IsBuiltIn, Blob); case MEMBER_TYPE_IS_TEMPLATE: return decodeRecord(R, I->IsTemplate, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for MemberTypeInfo"); } } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, CommentInfo *I) { llvm::SmallString<16> KindStr; switch (ID) { case COMMENT_KIND: if (llvm::Error Err = decodeRecord(R, KindStr, Blob)) return Err; I->Kind = stringToCommentKind(KindStr); return llvm::Error::success(); 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"); } } static 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_QUAL_NAME: return decodeRecord(R, I->QualName, 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); case REFERENCE_FILE: return decodeRecord(R, I->DocumentationFileName, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for Reference"); } } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, TemplateInfo *I) { // Currently there are no child records of TemplateInfo (only child blocks). return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for TemplateParamInfo"); } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, TemplateSpecializationInfo *I) { if (ID == TEMPLATE_SPECIALIZATION_OF) return decodeRecord(R, I->SpecializationOf, Blob); return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for TemplateParamInfo"); } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, TemplateParamInfo *I) { if (ID == TEMPLATE_PARAM_CONTENTS) return decodeRecord(R, I->Contents, Blob); return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for TemplateParamInfo"); } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, ConceptInfo *I) { switch (ID) { case CONCEPT_USR: return decodeRecord(R, I->USR, Blob); case CONCEPT_NAME: return decodeRecord(R, I->Name, Blob); case CONCEPT_IS_TYPE: return decodeRecord(R, I->IsType, Blob); case CONCEPT_CONSTRAINT_EXPRESSION: return decodeRecord(R, I->ConstraintExpression, Blob); } llvm_unreachable("invalid field for ConceptInfo"); } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, ConstraintInfo *I) { if (ID == CONSTRAINT_EXPRESSION) return decodeRecord(R, I->ConstraintExpr, Blob); return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for ConstraintInfo"); } static llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, VarInfo *I) { switch (ID) { case VAR_USR: return decodeRecord(R, I->USR, Blob); case VAR_NAME: return decodeRecord(R, I->Name, Blob); case VAR_DEFLOCATION: return decodeRecord(R, I->DefLoc, Blob); case VAR_IS_STATIC: return decodeRecord(R, I->IsStatic, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for VarInfo"); } } static llvm::Error parseRecord(const Record &R, unsigned ID, StringRef Blob, FriendInfo *F) { if (ID == FRIEND_IS_CLASS) { return decodeRecord(R, F->IsClass, Blob); } return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for Friend"); } template static llvm::Expected getCommentInfo(T I) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid type cannot contain CommentInfo"); } template <> llvm::Expected getCommentInfo(FunctionInfo *I) { return &I->Description.emplace_back(); } template <> llvm::Expected getCommentInfo(NamespaceInfo *I) { return &I->Description.emplace_back(); } template <> llvm::Expected getCommentInfo(RecordInfo *I) { return &I->Description.emplace_back(); } template <> llvm::Expected getCommentInfo(MemberTypeInfo *I) { return &I->Description.emplace_back(); } template <> llvm::Expected getCommentInfo(EnumInfo *I) { return &I->Description.emplace_back(); } template <> llvm::Expected getCommentInfo(TypedefInfo *I) { return &I->Description.emplace_back(); } template <> llvm::Expected getCommentInfo(EnumValueInfo *I) { return &I->Description.emplace_back(); } template <> llvm::Expected getCommentInfo(CommentInfo *I) { I->Children.emplace_back(std::make_unique()); return I->Children.back().get(); } template <> llvm::Expected getCommentInfo(ConceptInfo *I) { return &I->Description.emplace_back(); } template <> Expected getCommentInfo(VarInfo *I) { return &I->Description.emplace_back(); } // When readSubBlock encounters a TypeInfo sub-block, it calls addTypeInfo on // the parent block to set it. The template specializations define what to do // for each supported parent block. template static 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 <> llvm::Error addTypeInfo(FriendInfo *I, FieldTypeInfo &&T) { if (!I->Params) I->Params.emplace(); I->Params->emplace_back(std::move(T)); return llvm::Error::success(); } template <> llvm::Error addTypeInfo(FriendInfo *I, TypeInfo &&T) { I->ReturnType.emplace(std::move(T)); return llvm::Error::success(); } template <> llvm::Error addTypeInfo(EnumInfo *I, TypeInfo &&T) { I->BaseType = std::move(T); return llvm::Error::success(); } template <> llvm::Error addTypeInfo(TypedefInfo *I, TypeInfo &&T) { I->Underlying = std::move(T); return llvm::Error::success(); } template <> llvm::Error addTypeInfo(VarInfo *I, TypeInfo &&T) { I->Type = std::move(T); return llvm::Error::success(); } template static llvm::Error addReference(T I, Reference &&R, FieldId F) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid type cannot contain Reference"); } template <> llvm::Error addReference(VarInfo *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(), "VarInfo cannot contain this 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(TypedefInfo *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->Children.Namespaces.emplace_back(std::move(R)); return llvm::Error::success(); case FieldId::F_child_record: I->Children.Records.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->Children.Records.emplace_back(std::move(R)); return llvm::Error::success(); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid type cannot contain Reference"); } } template <> llvm::Error addReference(ConstraintInfo *I, Reference &&R, FieldId F) { if (F == FieldId::F_concept) { I->ConceptRef = std::move(R); return llvm::Error::success(); } return llvm::createStringError( llvm::inconvertibleErrorCode(), "ConstraintInfo cannot contain this Reference"); } template <> llvm::Error addReference(FriendInfo *Friend, Reference &&R, FieldId F) { if (F == FieldId::F_friend) { Friend->Ref = std::move(R); return llvm::Error::success(); } return llvm::createStringError(llvm::inconvertibleErrorCode(), "Friend cannot contain this Reference"); } template static void addChild(T I, ChildInfoType &&R) { llvm::errs() << "invalid child type for info"; exit(1); } // Namespace children: template <> void addChild(NamespaceInfo *I, FunctionInfo &&R) { I->Children.Functions.emplace_back(std::move(R)); } template <> void addChild(NamespaceInfo *I, EnumInfo &&R) { I->Children.Enums.emplace_back(std::move(R)); } template <> void addChild(NamespaceInfo *I, TypedefInfo &&R) { I->Children.Typedefs.emplace_back(std::move(R)); } template <> void addChild(NamespaceInfo *I, ConceptInfo &&R) { I->Children.Concepts.emplace_back(std::move(R)); } template <> void addChild(NamespaceInfo *I, VarInfo &&R) { I->Children.Variables.emplace_back(std::move(R)); } // Record children: template <> void addChild(RecordInfo *I, FunctionInfo &&R) { I->Children.Functions.emplace_back(std::move(R)); } template <> void addChild(RecordInfo *I, EnumInfo &&R) { I->Children.Enums.emplace_back(std::move(R)); } template <> void addChild(RecordInfo *I, TypedefInfo &&R) { I->Children.Typedefs.emplace_back(std::move(R)); } template <> void addChild(RecordInfo *I, FriendInfo &&R) { I->Friends.emplace_back(std::move(R)); } // Other types of children: template <> void addChild(EnumInfo *I, EnumValueInfo &&R) { I->Members.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->Children.Functions.emplace_back(std::move(R)); } // TemplateParam children. These go into either a TemplateInfo (for template // parameters) or TemplateSpecializationInfo (for the specialization's // parameters). template static void addTemplateParam(T I, TemplateParamInfo &&P) { llvm::errs() << "invalid container for template parameter"; exit(1); } template <> void addTemplateParam(TemplateInfo *I, TemplateParamInfo &&P) { I->Params.emplace_back(std::move(P)); } template <> void addTemplateParam(TemplateSpecializationInfo *I, TemplateParamInfo &&P) { I->Params.emplace_back(std::move(P)); } // Template info. These apply to either records or functions. template static void addTemplate(T I, TemplateInfo &&P) { llvm::errs() << "invalid container for template info"; exit(1); } template <> void addTemplate(RecordInfo *I, TemplateInfo &&P) { I->Template.emplace(std::move(P)); } template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) { I->Template.emplace(std::move(P)); } template <> void addTemplate(ConceptInfo *I, TemplateInfo &&P) { I->Template = std::move(P); } template <> void addTemplate(FriendInfo *I, TemplateInfo &&P) { I->Template.emplace(std::move(P)); } // Template specializations go only into template records. template static void addTemplateSpecialization(T I, TemplateSpecializationInfo &&TSI) { llvm::errs() << "invalid container for template specialization info"; exit(1); } template <> void addTemplateSpecialization(TemplateInfo *I, TemplateSpecializationInfo &&TSI) { I->Specialization.emplace(std::move(TSI)); } template static void addConstraint(T I, ConstraintInfo &&C) { llvm::errs() << "invalid container for constraint info"; exit(1); } template <> void addConstraint(TemplateInfo *I, ConstraintInfo &&C) { I->Constraints.emplace_back(std::move(C)); } // Read records from bitcode into a given info. template llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) { Record R; llvm::StringRef Blob; llvm::Expected 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) { llvm::TimeTraceScope("Reducing infos", "readRecord"); Record R; llvm::StringRef Blob; llvm::Expected 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 llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) { llvm::TimeTraceScope("Reducing infos", "readBlock"); 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; } } // TODO: fix inconsistentent returning of errors in add callbacks. // Once that's fixed, we only need one handleSubBlock. template llvm::Error ClangDocBitcodeReader::handleSubBlock(unsigned ID, T Parent, Callback Function) { InfoType Info; if (auto Err = readBlock(ID, &Info)) return Err; Function(Parent, std::move(Info)); return llvm::Error::success(); } template llvm::Error ClangDocBitcodeReader::handleTypeSubBlock(unsigned ID, T Parent, Callback Function) { InfoType Info; if (auto Err = readBlock(ID, &Info)) return Err; if (auto Err = Function(Parent, std::move(Info))) return Err; return llvm::Error::success(); } template llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { llvm::TimeTraceScope("Reducing infos", "readSubBlock"); static auto CreateAddFunc = [](auto AddFunc) { return [AddFunc](auto Parent, auto Child) { return AddFunc(Parent, std::move(Child)); }; }; switch (ID) { // Blocks can only have certain types of sub blocks. 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: { return handleTypeSubBlock( ID, I, CreateAddFunc(addTypeInfo)); } case BI_FIELD_TYPE_BLOCK_ID: { return handleTypeSubBlock( ID, I, CreateAddFunc(addTypeInfo)); } case BI_MEMBER_TYPE_BLOCK_ID: { return handleTypeSubBlock( ID, I, CreateAddFunc(addTypeInfo)); } 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: { return handleSubBlock( ID, I, CreateAddFunc(addChild)); } case BI_BASE_RECORD_BLOCK_ID: { return handleSubBlock( ID, I, CreateAddFunc(addChild)); } case BI_ENUM_BLOCK_ID: { return handleSubBlock(ID, I, CreateAddFunc(addChild)); } case BI_ENUM_VALUE_BLOCK_ID: { return handleSubBlock( ID, I, CreateAddFunc(addChild)); } case BI_TEMPLATE_BLOCK_ID: { return handleSubBlock(ID, I, CreateAddFunc(addTemplate)); } case BI_TEMPLATE_SPECIALIZATION_BLOCK_ID: { return handleSubBlock( ID, I, CreateAddFunc(addTemplateSpecialization)); } case BI_TEMPLATE_PARAM_BLOCK_ID: { return handleSubBlock( ID, I, CreateAddFunc(addTemplateParam)); } case BI_TYPEDEF_BLOCK_ID: { return handleSubBlock(ID, I, CreateAddFunc(addChild)); } case BI_CONSTRAINT_BLOCK_ID: { return handleSubBlock(ID, I, CreateAddFunc(addConstraint)); } case BI_CONCEPT_BLOCK_ID: { return handleSubBlock(ID, I, CreateAddFunc(addChild)); } case BI_VAR_BLOCK_ID: { return handleSubBlock(ID, I, CreateAddFunc(addChild)); } case BI_FRIEND_BLOCK_ID: { return handleSubBlock(ID, I, CreateAddFunc(addChild)); } default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid subblock type"); } } ClangDocBitcodeReader::Cursor ClangDocBitcodeReader::skipUntilRecordOrBlock(unsigned &BlockOrRecordID) { llvm::TimeTraceScope("Reducing infos", "skipUntilRecordOrBlock"); BlockOrRecordID = 0; while (!Stream.AtEndOfStream()) { Expected 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(llvm::bitc::FIRST_APPLICATION_ABBREV)) { BlockOrRecordID = Code; return Cursor::Record; } switch (static_cast(Code)) { case llvm::bitc::ENTER_SUBBLOCK: if (Expected 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 MaybeRead = Stream.Read(8); if (!MaybeRead) return MaybeRead.takeError(); if (MaybeRead.get() != BitCodeConstants::Signature[Idx]) return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid bitcode signature"); } return llvm::Error::success(); } llvm::Error ClangDocBitcodeReader::readBlockInfoBlock() { llvm::TimeTraceScope("Reducing infos", "readBlockInfoBlock"); Expected> MaybeBlockInfo = Stream.ReadBlockInfoBlock(); if (!MaybeBlockInfo) return MaybeBlockInfo.takeError(); BlockInfo = MaybeBlockInfo.get(); if (!BlockInfo) return llvm::createStringError(llvm::inconvertibleErrorCode(), "unable to parse BlockInfoBlock"); Stream.setBlockInfo(&*BlockInfo); return llvm::Error::success(); } template llvm::Expected> ClangDocBitcodeReader::createInfo(unsigned ID) { llvm::TimeTraceScope("Reducing infos", "createInfo"); std::unique_ptr I = std::make_unique(); if (auto Err = readBlock(ID, static_cast(I.get()))) return std::move(Err); return std::unique_ptr{std::move(I)}; } llvm::Expected> ClangDocBitcodeReader::readBlockToInfo(unsigned ID) { llvm::TimeTraceScope("Reducing infos", "readBlockToInfo"); switch (ID) { case BI_NAMESPACE_BLOCK_ID: return createInfo(ID); case BI_RECORD_BLOCK_ID: return createInfo(ID); case BI_ENUM_BLOCK_ID: return createInfo(ID); case BI_TYPEDEF_BLOCK_ID: return createInfo(ID); case BI_CONCEPT_BLOCK_ID: return createInfo(ID); case BI_FUNCTION_BLOCK_ID: return createInfo(ID); case BI_VAR_BLOCK_ID: return createInfo(ID); case BI_FRIEND_BLOCK_ID: return createInfo(ID); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "cannot create info"); } } // Entry point llvm::Expected>> ClangDocBitcodeReader::readBitcode() { std::vector> Infos; if (auto Err = validateStream()) return std::move(Err); // Read the top level blocks. while (!Stream.AtEndOfStream()) { Expected 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 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_TYPEDEF_BLOCK_ID: case BI_CONCEPT_BLOCK_ID: case BI_VAR_BLOCK_ID: case BI_FRIEND_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