//===--- PCHReaderDecl.cpp - Decl Deserialization ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the PCHReader::ReadDeclRecord method, which is the // entrypoint for loading a decl. // //===----------------------------------------------------------------------===// #include "clang/Frontend/PCHReader.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/Expr.h" using namespace clang; // FIXME: Temporarily cloned from PCHReader.cpp. namespace { /// \brief Helper class that saves the current stream position and /// then restores it when destroyed. struct SavedStreamPosition { explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor) : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { } ~SavedStreamPosition() { Cursor.JumpToBit(Offset); } private: llvm::BitstreamCursor &Cursor; uint64_t Offset; }; } //===----------------------------------------------------------------------===// // Declaration deserialization //===----------------------------------------------------------------------===// namespace { class PCHDeclReader : public DeclVisitor { PCHReader &Reader; const PCHReader::RecordData &Record; unsigned &Idx; public: PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record, unsigned &Idx) : Reader(Reader), Record(Record), Idx(Idx) { } void VisitDecl(Decl *D); void VisitTranslationUnitDecl(TranslationUnitDecl *TU); void VisitNamedDecl(NamedDecl *ND); void VisitTypeDecl(TypeDecl *TD); void VisitTypedefDecl(TypedefDecl *TD); void VisitTagDecl(TagDecl *TD); void VisitEnumDecl(EnumDecl *ED); void VisitRecordDecl(RecordDecl *RD); void VisitValueDecl(ValueDecl *VD); void VisitEnumConstantDecl(EnumConstantDecl *ECD); void VisitFunctionDecl(FunctionDecl *FD); void VisitFieldDecl(FieldDecl *FD); void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); void VisitOriginalParmVarDecl(OriginalParmVarDecl *PD); void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); void VisitBlockDecl(BlockDecl *BD); std::pair VisitDeclContext(DeclContext *DC); void VisitObjCMethodDecl(ObjCMethodDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); void VisitObjCIvarDecl(ObjCIvarDecl *D); void VisitObjCProtocolDecl(ObjCProtocolDecl *D); void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D); void VisitObjCClassDecl(ObjCClassDecl *D); void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); void VisitObjCCategoryDecl(ObjCCategoryDecl *D); void VisitObjCImplDecl(ObjCImplDecl *D); void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); void VisitObjCImplementationDecl(ObjCImplementationDecl *D); void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); }; } void PCHDeclReader::VisitDecl(Decl *D) { D->setDeclContext(cast_or_null(Reader.GetDecl(Record[Idx++]))); D->setLexicalDeclContext( cast_or_null(Reader.GetDecl(Record[Idx++]))); D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); D->setInvalidDecl(Record[Idx++]); if (Record[Idx++]) D->addAttr(Reader.ReadAttributes()); D->setImplicit(Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]); } void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { VisitDecl(TU); } void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) { VisitDecl(ND); ND->setDeclName(Reader.ReadDeclarationName(Record, Idx)); } void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) { VisitNamedDecl(TD); TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr()); } void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { // Note that we cannot use VisitTypeDecl here, because we need to // set the underlying type of the typedef *before* we try to read // the type associated with the TypedefDecl. VisitNamedDecl(TD); TD->setUnderlyingType(Reader.GetType(Record[Idx + 1])); TD->setTypeForDecl(Reader.GetType(Record[Idx]).getTypePtr()); Idx += 2; } void PCHDeclReader::VisitTagDecl(TagDecl *TD) { VisitTypeDecl(TD); TD->setTagKind((TagDecl::TagKind)Record[Idx++]); TD->setDefinition(Record[Idx++]); TD->setTypedefForAnonDecl( cast_or_null(Reader.GetDecl(Record[Idx++]))); } void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { VisitTagDecl(ED); ED->setIntegerType(Reader.GetType(Record[Idx++])); } void PCHDeclReader::VisitRecordDecl(RecordDecl *RD) { VisitTagDecl(RD); RD->setHasFlexibleArrayMember(Record[Idx++]); RD->setAnonymousStructOrUnion(Record[Idx++]); } void PCHDeclReader::VisitValueDecl(ValueDecl *VD) { VisitNamedDecl(VD); VD->setType(Reader.GetType(Record[Idx++])); } void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { VisitValueDecl(ECD); if (Record[Idx++]) ECD->setInitExpr(Reader.ReadExpr()); ECD->setInitVal(Reader.ReadAPSInt(Record, Idx)); } void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { VisitValueDecl(FD); if (Record[Idx++]) FD->setLazyBody(Reader.getStream().GetCurrentBitNo()); FD->setPreviousDeclaration( cast_or_null(Reader.GetDecl(Record[Idx++]))); FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]); FD->setInline(Record[Idx++]); FD->setC99InlineDefinition(Record[Idx++]); FD->setVirtual(Record[Idx++]); FD->setPure(Record[Idx++]); FD->setInheritedPrototype(Record[Idx++]); FD->setHasPrototype(Record[Idx++]); FD->setDeleted(Record[Idx++]); FD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); unsigned NumParams = Record[Idx++]; llvm::SmallVector Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); FD->setParams(Reader.getContext(), &Params[0], NumParams); } void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { VisitNamedDecl(MD); if (Record[Idx++]) { // In practice, this won't be executed (since method definitions // don't occur in header files). MD->setBody(Reader.ReadStmt()); MD->setSelfDecl(cast(Reader.GetDecl(Record[Idx++]))); MD->setCmdDecl(cast(Reader.GetDecl(Record[Idx++]))); } MD->setInstanceMethod(Record[Idx++]); MD->setVariadic(Record[Idx++]); MD->setSynthesized(Record[Idx++]); MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]); MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); MD->setResultType(Reader.GetType(Record[Idx++])); MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); unsigned NumParams = Record[Idx++]; llvm::SmallVector Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); MD->setMethodParams(Reader.getContext(), &Params[0], NumParams); } void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { VisitNamedDecl(CD); CD->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { VisitObjCContainerDecl(ID); ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr()); ID->setSuperClass(cast_or_null (Reader.GetDecl(Record[Idx++]))); unsigned NumProtocols = Record[Idx++]; llvm::SmallVector Protocols; Protocols.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) Protocols.push_back(cast(Reader.GetDecl(Record[Idx++]))); ID->setProtocolList(&Protocols[0], NumProtocols, Reader.getContext()); unsigned NumIvars = Record[Idx++]; llvm::SmallVector IVars; IVars.reserve(NumIvars); for (unsigned I = 0; I != NumIvars; ++I) IVars.push_back(cast(Reader.GetDecl(Record[Idx++]))); ID->setIVarList(&IVars[0], NumIvars, Reader.getContext()); ID->setCategoryList( cast_or_null(Reader.GetDecl(Record[Idx++]))); ID->setForwardDecl(Record[Idx++]); ID->setImplicitInterfaceDecl(Record[Idx++]); ID->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); ID->setSuperClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); ID->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void PCHDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) { VisitFieldDecl(IVD); IVD->setAccessControl((ObjCIvarDecl::AccessControl)Record[Idx++]); } void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { VisitObjCContainerDecl(PD); PD->setForwardDecl(Record[Idx++]); PD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); unsigned NumProtoRefs = Record[Idx++]; llvm::SmallVector ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); PD->setProtocolList(&ProtoRefs[0], NumProtoRefs, Reader.getContext()); } void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { VisitFieldDecl(FD); } void PCHDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) { VisitDecl(CD); unsigned NumClassRefs = Record[Idx++]; llvm::SmallVector ClassRefs; ClassRefs.reserve(NumClassRefs); for (unsigned I = 0; I != NumClassRefs; ++I) ClassRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); CD->setClassList(Reader.getContext(), &ClassRefs[0], NumClassRefs); } void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { VisitDecl(FPD); unsigned NumProtoRefs = Record[Idx++]; llvm::SmallVector ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); FPD->setProtocolList(&ProtoRefs[0], NumProtoRefs, Reader.getContext()); } void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { VisitObjCContainerDecl(CD); CD->setClassInterface(cast(Reader.GetDecl(Record[Idx++]))); unsigned NumProtoRefs = Record[Idx++]; llvm::SmallVector ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); CD->setProtocolList(&ProtoRefs[0], NumProtoRefs, Reader.getContext()); CD->setNextClassCategory(cast_or_null(Reader.GetDecl(Record[Idx++]))); CD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); } void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { VisitNamedDecl(CAD); CAD->setClassInterface(cast(Reader.GetDecl(Record[Idx++]))); } void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); D->setType(Reader.GetType(Record[Idx++])); // FIXME: stable encoding D->setPropertyAttributes( (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]); // FIXME: stable encoding D->setPropertyImplementation( (ObjCPropertyDecl::PropertyControl)Record[Idx++]); D->setGetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); D->setSetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); D->setGetterMethodDecl( cast_or_null(Reader.GetDecl(Record[Idx++]))); D->setSetterMethodDecl( cast_or_null(Reader.GetDecl(Record[Idx++]))); D->setPropertyIvarDecl( cast_or_null(Reader.GetDecl(Record[Idx++]))); } void PCHDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) { VisitNamedDecl(D); D->setClassInterface( cast_or_null(Reader.GetDecl(Record[Idx++]))); D->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); } void PCHDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitObjCImplDecl(D); D->setIdentifier(Reader.GetIdentifierInfo(Record, Idx)); } void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); D->setSuperClass( cast_or_null(Reader.GetDecl(Record[Idx++]))); } void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { VisitDecl(D); D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); D->setPropertyDecl( cast_or_null(Reader.GetDecl(Record[Idx++]))); D->setPropertyIvarDecl( cast_or_null(Reader.GetDecl(Record[Idx++]))); } void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitValueDecl(FD); FD->setMutable(Record[Idx++]); if (Record[Idx++]) FD->setBitWidth(Reader.ReadExpr()); } void PCHDeclReader::VisitVarDecl(VarDecl *VD) { VisitValueDecl(VD); VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]); VD->setThreadSpecified(Record[Idx++]); VD->setCXXDirectInitializer(Record[Idx++]); VD->setDeclaredInCondition(Record[Idx++]); VD->setPreviousDeclaration( cast_or_null(Reader.GetDecl(Record[Idx++]))); VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); if (Record[Idx++]) VD->setInit(Reader.ReadExpr()); } void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { VisitVarDecl(PD); } void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { VisitVarDecl(PD); PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); // FIXME: default argument (C++ only) } void PCHDeclReader::VisitOriginalParmVarDecl(OriginalParmVarDecl *PD) { VisitParmVarDecl(PD); PD->setOriginalType(Reader.GetType(Record[Idx++])); } void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { VisitDecl(AD); AD->setAsmString(cast(Reader.ReadExpr())); } void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) { VisitDecl(BD); BD->setBody(cast_or_null(Reader.ReadStmt())); unsigned NumParams = Record[Idx++]; llvm::SmallVector Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); BD->setParams(Reader.getContext(), &Params[0], NumParams); } std::pair PCHDeclReader::VisitDeclContext(DeclContext *DC) { uint64_t LexicalOffset = Record[Idx++]; uint64_t VisibleOffset = Record[Idx++]; return std::make_pair(LexicalOffset, VisibleOffset); } //===----------------------------------------------------------------------===// // PCHReader Implementation //===----------------------------------------------------------------------===// /// \brief Note that we have loaded the declaration with the given /// Index. /// /// This routine notes that this declaration has already been loaded, /// so that future GetDecl calls will return this declaration rather /// than trying to load a new declaration. inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) { assert(!DeclsLoaded[Index] && "Decl loaded twice?"); DeclsLoaded[Index] = D; } /// \brief Determine whether the consumer will be interested in seeing /// this declaration (via HandleTopLevelDecl). /// /// This routine should return true for anything that might affect /// code generation, e.g., inline function definitions, Objective-C /// declarations with metadata, etc. static bool isConsumerInterestedIn(Decl *D) { if (VarDecl *Var = dyn_cast(D)) return Var->isFileVarDecl() && Var->getInit(); if (FunctionDecl *Func = dyn_cast(D)) return Func->isThisDeclarationADefinition(); return isa(D); } /// \brief Read the declaration at the given offset from the PCH file. Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { // Keep track of where we are in the stream, then jump back there // after reading this declaration. SavedStreamPosition SavedPosition(Stream); Decl *D = 0; Stream.JumpToBit(Offset); RecordData Record; unsigned Code = Stream.ReadCode(); unsigned Idx = 0; PCHDeclReader Reader(*this, Record, Idx); switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) { case pch::DECL_ATTR: case pch::DECL_CONTEXT_LEXICAL: case pch::DECL_CONTEXT_VISIBLE: assert(false && "Record cannot be de-serialized with ReadDeclRecord"); break; case pch::DECL_TRANSLATION_UNIT: assert(Index == 0 && "Translation unit must be at index 0"); D = Context.getTranslationUnitDecl(); break; case pch::DECL_TYPEDEF: { D = TypedefDecl::Create(Context, 0, SourceLocation(), 0, QualType()); break; } case pch::DECL_ENUM: { D = EnumDecl::Create(Context, 0, SourceLocation(), 0, 0); break; } case pch::DECL_RECORD: { D = RecordDecl::Create(Context, TagDecl::TK_struct, 0, SourceLocation(), 0, 0); break; } case pch::DECL_ENUM_CONSTANT: { D = EnumConstantDecl::Create(Context, 0, SourceLocation(), 0, QualType(), 0, llvm::APSInt()); break; } case pch::DECL_FUNCTION: { D = FunctionDecl::Create(Context, 0, SourceLocation(), DeclarationName(), QualType()); break; } case pch::DECL_OBJC_METHOD: { D = ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(), Selector(), QualType(), 0); break; } case pch::DECL_OBJC_INTERFACE: { D = ObjCInterfaceDecl::Create(Context, 0, SourceLocation(), 0); break; } case pch::DECL_OBJC_IVAR: { D = ObjCIvarDecl::Create(Context, 0, SourceLocation(), 0, QualType(), ObjCIvarDecl::None); break; } case pch::DECL_OBJC_PROTOCOL: { D = ObjCProtocolDecl::Create(Context, 0, SourceLocation(), 0); break; } case pch::DECL_OBJC_AT_DEFS_FIELD: { D = ObjCAtDefsFieldDecl::Create(Context, 0, SourceLocation(), 0, QualType(), 0); break; } case pch::DECL_OBJC_CLASS: { D = ObjCClassDecl::Create(Context, 0, SourceLocation()); break; } case pch::DECL_OBJC_FORWARD_PROTOCOL: { D = ObjCForwardProtocolDecl::Create(Context, 0, SourceLocation()); break; } case pch::DECL_OBJC_CATEGORY: { D = ObjCCategoryDecl::Create(Context, 0, SourceLocation(), 0); break; } case pch::DECL_OBJC_CATEGORY_IMPL: { D = ObjCCategoryImplDecl::Create(Context, 0, SourceLocation(), 0, 0); break; } case pch::DECL_OBJC_IMPLEMENTATION: { D = ObjCImplementationDecl::Create(Context, 0, SourceLocation(), 0, 0); break; } case pch::DECL_OBJC_COMPATIBLE_ALIAS: { D = ObjCCompatibleAliasDecl::Create(Context, 0, SourceLocation(), 0, 0); break; } case pch::DECL_OBJC_PROPERTY: { D = ObjCPropertyDecl::Create(Context, 0, SourceLocation(), 0, QualType()); break; } case pch::DECL_OBJC_PROPERTY_IMPL: { D = ObjCPropertyImplDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, ObjCPropertyImplDecl::Dynamic, 0); break; } case pch::DECL_FIELD: { D = FieldDecl::Create(Context, 0, SourceLocation(), 0, QualType(), 0, false); break; } case pch::DECL_VAR: D = VarDecl::Create(Context, 0, SourceLocation(), 0, QualType(), VarDecl::None, SourceLocation()); break; case pch::DECL_IMPLICIT_PARAM: D = ImplicitParamDecl::Create(Context, 0, SourceLocation(), 0, QualType()); break; case pch::DECL_PARM_VAR: { D = ParmVarDecl::Create(Context, 0, SourceLocation(), 0, QualType(), VarDecl::None, 0); break; } case pch::DECL_ORIGINAL_PARM_VAR: { D = OriginalParmVarDecl::Create(Context, 0, SourceLocation(), 0, QualType(), QualType(), VarDecl::None, 0); break; } case pch::DECL_FILE_SCOPE_ASM: { D = FileScopeAsmDecl::Create(Context, 0, SourceLocation(), 0); break; } case pch::DECL_BLOCK: { D = BlockDecl::Create(Context, 0, SourceLocation()); break; } } assert(D && "Unknown declaration reading PCH file"); if (D) { LoadedDecl(Index, D); Reader.Visit(D); } // If this declaration is also a declaration context, get the // offsets for its tables of lexical and visible declarations. if (DeclContext *DC = dyn_cast(D)) { std::pair Offsets = Reader.VisitDeclContext(DC); if (Offsets.first || Offsets.second) { DC->setHasExternalLexicalStorage(Offsets.first != 0); DC->setHasExternalVisibleStorage(Offsets.second != 0); DeclContextOffsets[DC] = Offsets; } } assert(Idx == Record.size()); // If we have deserialized a declaration that has a definition the // AST consumer might need to know about, notify the consumer // about that definition now or queue it for later. if (isConsumerInterestedIn(D)) { if (Consumer) { DeclGroupRef DG(D); Consumer->HandleTopLevelDecl(DG); } else { InterestingDecls.push_back(D); } } return D; }