/************************************************************************ * * CppSharp * Licensed under the simplified BSD license. All rights reserved. * ************************************************************************/ #include "Parser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace CppSharp::CppParser; //-----------------------------------// Parser::Parser(ParserOptions* Opts) : Lib(Opts->ASTContext), Opts(Opts), Index(0) { } //-----------------------------------// static std::string GetClangResourceDir(const std::string& Dir) { using namespace llvm; using namespace clang; // Compute the path to the resource directory. StringRef ClangResourceDir(CLANG_RESOURCE_DIR); SmallString<128> P(Dir); if (ClangResourceDir != "") llvm::sys::path::append(P, ClangResourceDir); else llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING); return P.str(); } static std::string GetClangBuiltinIncludeDir() { using namespace llvm; SmallString<128> P( GetClangResourceDir(".") ); llvm::sys::path::append(P, "include"); return P.str(); } //-----------------------------------// static std::string GetCXXABIString(clang::TargetCXXABI::Kind Kind) { switch(Kind) { case clang::TargetCXXABI::GenericItanium: return "itanium"; case clang::TargetCXXABI::Microsoft: return "microsoft"; } llvm_unreachable("Unknown C++ ABI kind"); } #ifdef _MSC_VER std::vector GetWindowsSystemIncludeDirs(); #endif void Parser::SetupHeader() { using namespace clang; std::vector args; args.push_back("-cc1"); // Enable C++ language mode args.push_back("-xc++"); args.push_back("-std=gnu++11"); args.push_back("-fno-rtti"); for (unsigned I = 0, E = Opts->Arguments.size(); I != E; ++I) { const String& Arg = Opts->Arguments[I]; args.push_back(Arg.c_str()); } // Enable the Microsoft parsing extensions if (Opts->MicrosoftMode) { args.push_back("-fms-extensions"); args.push_back("-fms-compatibility"); args.push_back("-fdelayed-template-parsing"); } C.reset(new CompilerInstance()); C->createDiagnostics(); CompilerInvocation* Inv = new CompilerInvocation(); CompilerInvocation::CreateFromArgs(*Inv, args.data(), args.data() + args.size(), C->getDiagnostics()); C->setInvocation(Inv); TargetOptions& TO = Inv->getTargetOpts(); TargetABI = (Opts->Abi == CppAbi::Microsoft) ? TargetCXXABI::Microsoft : TargetCXXABI::GenericItanium; TO.Triple = llvm::sys::getDefaultTargetTriple(); if (!Opts->TargetTriple.empty()) TO.Triple = Opts->TargetTriple; TargetInfo* TI = TargetInfo::CreateTargetInfo(C->getDiagnostics(), &TO); if (!TI) { // We might have no target info due to an invalid user-provided triple. // Try again with the default triple. TO.Triple = llvm::sys::getDefaultTargetTriple(); TI = TargetInfo::CreateTargetInfo(C->getDiagnostics(), &TO); } assert(TI && "Expected valid target info"); TI->setCXXABI(TargetABI); C->setTarget(TI); C->createFileManager(); C->createSourceManager(C->getFileManager()); auto& HSOpts = C->getHeaderSearchOpts(); auto& PPOpts = C->getPreprocessorOpts(); auto& LangOpts = C->getLangOpts(); if (Opts->NoStandardIncludes) { HSOpts.UseStandardSystemIncludes = false; HSOpts.UseStandardCXXIncludes = false; } if (Opts->NoBuiltinIncludes) HSOpts.UseBuiltinIncludes = false; if (Opts->Verbose) HSOpts.Verbose = true; for (unsigned I = 0, E = Opts->IncludeDirs.size(); I != E; ++I) { const String& s = Opts->IncludeDirs[I]; HSOpts.AddPath(s, frontend::Angled, false, false); } for (unsigned I = 0, E = Opts->SystemIncludeDirs.size(); I != E; ++I) { String s = Opts->SystemIncludeDirs[I]; HSOpts.AddPath(s, frontend::System, false, false); } for (unsigned I = 0, E = Opts->Defines.size(); I != E; ++I) { const String& define = Opts->Defines[I]; PPOpts.addMacroDef(define); } // Initialize the default platform headers. HSOpts.ResourceDir = GetClangResourceDir("."); HSOpts.AddPath(GetClangBuiltinIncludeDir(), clang::frontend::System, /*IsFramework=*/false, /*IgnoreSysRoot=*/false); #ifdef _MSC_VER if (!Opts->NoBuiltinIncludes) { std::vector SystemDirs = GetWindowsSystemIncludeDirs(); for(unsigned i = 0; i < SystemDirs.size(); i++) HSOpts.AddPath(SystemDirs[i], frontend::System, /*IsFramework=*/false, /*IgnoreSysRoot=*/false); } if (Opts->MicrosoftMode) { LangOpts.MSCVersion = Opts->ToolSetToUse; if (!LangOpts.MSCVersion) LangOpts.MSCVersion = 1700; } #endif // Enable preprocessing record. PPOpts.DetailedRecord = true; C->createPreprocessor(); Preprocessor& PP = C->getPreprocessor(); PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), PP.getLangOpts()); C->createASTContext(); } //-----------------------------------// std::string Parser::GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI, bool IsDependent) { using namespace clang; if(!D || !isa(D)) return ""; bool CanMangle = isa(D) || isa(D) || isa(D) || isa(D); if (!CanMangle) return ""; NamedDecl* ND = cast(D); llvm::OwningPtr MC; switch(ABI.getKind()) { default: llvm_unreachable("Unknown mangling ABI"); break; case TargetCXXABI::GenericItanium: MC.reset(ItaniumMangleContext::create(*AST, AST->getDiagnostics())); break; case TargetCXXABI::Microsoft: MC.reset(MicrosoftMangleContext::create(*AST, AST->getDiagnostics())); break; } std::string Mangled; llvm::raw_string_ostream Out(Mangled); if (const ValueDecl *VD = dyn_cast(ND)) IsDependent = VD->getType()->isDependentType(); if (!MC->shouldMangleDeclName(ND) || IsDependent) return ND->getDeclName().getAsString(); if (const CXXConstructorDecl *CD = dyn_cast(ND)) MC->mangleCXXCtor(CD, Ctor_Base, Out); else if (const CXXDestructorDecl *DD = dyn_cast(ND)) MC->mangleCXXDtor(DD, Dtor_Base, Out); else MC->mangleName(ND, Out); Out.flush(); // Strip away LLVM name marker. if(!Mangled.empty() && Mangled[0] == '\01') Mangled = Mangled.substr(1); return Mangled; } //-----------------------------------// static std::string GetDeclName(const clang::NamedDecl* D) { if (const clang::IdentifierInfo *II = D->getIdentifier()) return II->getName(); return D->getNameAsString(); } static std::string GetTagDeclName(const clang::TagDecl* D) { using namespace clang; if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) { assert(Typedef->getIdentifier() && "Typedef without identifier?"); return GetDeclName(Typedef); } return GetDeclName(D); } static clang::Decl* GetPreviousDeclInContext(const clang::Decl* D) { assert(!D->getLexicalDeclContext()->decls_empty()); clang::Decl* prevDecl = nullptr; for(auto it = D->getDeclContext()->decls_begin(); it != D->getDeclContext()->decls_end(); it++) { if((*it) == D) return prevDecl; prevDecl = (*it); } return nullptr; } static clang::SourceLocation GetDeclStartLocation(clang::CompilerInstance* C, const clang::Decl* D) { auto &SM = C->getSourceManager(); auto startLoc = SM.getExpansionLoc(D->getLocStart()); auto startOffset = SM.getFileOffset(startLoc); if (clang::dyn_cast_or_null(D)) return startLoc; auto lineNo = SM.getExpansionLineNumber(startLoc); auto lineBeginLoc = SM.translateLineCol(SM.getFileID(startLoc), lineNo, 1); auto lineBeginOffset = SM.getFileOffset(lineBeginLoc); assert(lineBeginOffset <= startOffset); if (D->getLexicalDeclContext()->decls_empty()) return lineBeginLoc; auto prevDecl = GetPreviousDeclInContext(D); if(!prevDecl) return lineBeginLoc; auto prevDeclEndLoc = SM.getExpansionLoc(prevDecl->getLocEnd()); auto prevDeclEndOffset = SM.getFileOffset(prevDeclEndLoc); if(SM.getFileID(prevDeclEndLoc) != SM.getFileID(startLoc)) return lineBeginLoc; // TODO: Figure out why this asserts //assert(prevDeclEndOffset <= startOffset); if(prevDeclEndOffset < lineBeginOffset) return lineBeginLoc; // Declarations don't share same macro expansion if(SM.getExpansionLoc(prevDecl->getLocStart()) != startLoc) return prevDeclEndLoc; return GetDeclStartLocation(C, prevDecl); } std::string Parser::GetTypeName(const clang::Type* Type) { using namespace clang; if(Type->isAnyPointerType() || Type->isReferenceType()) Type = Type->getPointeeType().getTypePtr(); if(Type->isEnumeralType() || Type->isRecordType()) { const clang::TagType* Tag = Type->getAs(); return GetTagDeclName(Tag->getDecl()); } PrintingPolicy pp(C->getLangOpts()); pp.SuppressTagKeyword = true; std::string TypeName; QualType::getAsStringInternal(Type, Qualifiers(), TypeName, pp); return TypeName; } static TypeQualifiers GetTypeQualifiers(clang::QualType Type) { TypeQualifiers quals; quals.IsConst = Type.isLocalConstQualified(); quals.IsRestrict = Type.isLocalRestrictQualified(); quals.IsVolatile = Type.isVolatileQualified(); return quals; } static QualifiedType GetQualifiedType(clang::QualType qual, Type* type) { QualifiedType qualType; qualType.Type = type; qualType.Qualifiers = GetTypeQualifiers(qual); return qualType; } //-----------------------------------// static AccessSpecifier ConvertToAccess(clang::AccessSpecifier AS) { switch(AS) { case clang::AS_private: return AccessSpecifier::Private; case clang::AS_protected: return AccessSpecifier::Protected; case clang::AS_public: return AccessSpecifier::Public; } return AccessSpecifier::Public; } VTableComponent Parser::WalkVTableComponent(const clang::VTableComponent& Component) { using namespace clang; VTableComponent VTC; switch(Component.getKind()) { case clang::VTableComponent::CK_VCallOffset: { VTC.Kind = VTableComponentKind::VBaseOffset; VTC.Offset = Component.getVCallOffset().getQuantity(); break; } case clang::VTableComponent::CK_VBaseOffset: { VTC.Kind = VTableComponentKind::VBaseOffset; VTC.Offset = Component.getVBaseOffset().getQuantity(); break; } case clang::VTableComponent::CK_OffsetToTop: { VTC.Kind = VTableComponentKind::OffsetToTop; VTC.Offset = Component.getOffsetToTop().getQuantity(); break; } case clang::VTableComponent::CK_RTTI: { VTC.Kind = VTableComponentKind::RTTI; auto RD = const_cast(Component.getRTTIDecl()); VTC.Declaration = WalkRecordCXX(RD); break; } case clang::VTableComponent::CK_FunctionPointer: { VTC.Kind = VTableComponentKind::FunctionPointer; auto MD = const_cast(Component.getFunctionDecl()); VTC.Declaration = WalkMethodCXX(MD); break; } case clang::VTableComponent::CK_CompleteDtorPointer: { VTC.Kind = VTableComponentKind::CompleteDtorPointer; auto MD = const_cast(Component.getDestructorDecl()); VTC.Declaration = WalkMethodCXX(MD); break; } case clang::VTableComponent::CK_DeletingDtorPointer: { VTC.Kind = VTableComponentKind::DeletingDtorPointer; auto MD = const_cast(Component.getDestructorDecl()); VTC.Declaration = WalkMethodCXX(MD); break; } case clang::VTableComponent::CK_UnusedFunctionPointer: { VTC.Kind = VTableComponentKind::UnusedFunctionPointer; auto MD = const_cast(Component.getUnusedFunctionDecl()); VTC.Declaration = WalkMethodCXX(MD); break; } default: llvm_unreachable("Unknown vtable component kind"); } return VTC; } VTableLayout Parser::WalkVTableLayout(const clang::VTableLayout& VTLayout) { auto Layout = VTableLayout(); for (auto I = VTLayout.vtable_component_begin(), E = VTLayout.vtable_component_end(); I != E; ++I) { auto VTComponent = WalkVTableComponent(*I); Layout.Components.push_back(VTComponent); } return Layout; } void Parser::WalkVTable(clang::CXXRecordDecl* RD, Class* C) { using namespace clang; assert(RD->isDynamicClass() && "Only dynamic classes have virtual tables"); switch(TargetABI) { case TargetCXXABI::Microsoft: { C->Layout.ABI = CppAbi::Microsoft; MicrosoftVTableContext VTContext(*AST); auto VFPtrs = VTContext.getVFPtrOffsets(RD); for (auto I = VFPtrs.begin(), E = VFPtrs.end(); I != E; ++I) { auto& VFPtrInfo = *I; VFTableInfo Info; Info.VFPtrOffset = VFPtrInfo->NonVirtualOffset.getQuantity(); Info.VFPtrFullOffset = VFPtrInfo->FullOffsetInMDC.getQuantity(); auto& VTLayout = VTContext.getVFTableLayout(RD, VFPtrInfo->FullOffsetInMDC); Info.Layout = WalkVTableLayout(VTLayout); C->Layout.VFTables.push_back(Info); } break; } case TargetCXXABI::GenericItanium: { C->Layout.ABI = CppAbi::Itanium; ItaniumVTableContext VTContext(*AST); auto& VTLayout = VTContext.getVTableLayout(RD); C->Layout.Layout = WalkVTableLayout(VTLayout); break; } default: llvm_unreachable("Unsupported C++ ABI kind"); } } Class* Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) { using namespace clang; if (Record->isInjectedClassName()) return nullptr; auto NS = GetNamespace(Record); assert(NS && "Expected a valid namespace"); bool isCompleteDefinition = Record->isCompleteDefinition(); Class* RC = nullptr; auto Name = GetTagDeclName(Record); auto HasEmptyName = Record->getDeclName().isEmpty(); if (HasEmptyName) { if (auto AR = NS->FindAnonymous((uint64_t)Record)) RC = static_cast(AR); } else { RC = NS->FindClass(Name, isCompleteDefinition, /*Create=*/false); } if (RC) return RC; RC = NS->FindClass(Name, isCompleteDefinition, /*Create=*/true); HandleDeclaration(Record, RC); if (HasEmptyName) NS->Anonymous[(uint64_t)Record] = RC; if (!isCompleteDefinition) return RC; WalkRecordCXX(Record, RC); return RC; } void Parser::WalkRecordCXX(clang::CXXRecordDecl* Record, Class* RC) { using namespace clang; auto headStartLoc = GetDeclStartLocation(C.get(), Record); auto headEndLoc = Record->getLocation(); // identifier location auto bodyEndLoc = Record->getLocEnd(); auto headRange = clang::SourceRange(headStartLoc, headEndLoc); auto bodyRange = clang::SourceRange(headEndLoc, bodyEndLoc); HandlePreprocessedEntities(RC, headRange, MacroLocation::ClassHead); HandlePreprocessedEntities(RC, bodyRange, MacroLocation::ClassBody); auto &Sema = C->getSema(); Sema.ForceDeclarationOfImplicitMembers(Record); RC->IsPOD = Record->isPOD(); RC->IsUnion = Record->isUnion(); RC->IsAbstract = Record->isAbstract(); RC->IsDependent = Record->isDependentType(); RC->IsDynamic = Record->isDynamicClass(); RC->IsPolymorphic = Record->isPolymorphic(); RC->HasNonTrivialDefaultConstructor = Record->hasNonTrivialDefaultConstructor(); RC->HasNonTrivialCopyConstructor = Record->hasNonTrivialCopyConstructor(); RC->HasNonTrivialDestructor = Record->hasNonTrivialDestructor(); RC->IsExternCContext = Record->isExternCContext(); bool hasLayout = !Record->isDependentType() && !Record->isInvalidDecl(); // Get the record layout information. const ASTRecordLayout* Layout = 0; if (hasLayout) { Layout = &C->getASTContext().getASTRecordLayout(Record); RC->Layout.Alignment = (int)Layout-> getAlignment().getQuantity(); RC->Layout.Size = (int)Layout->getSize().getQuantity(); RC->Layout.DataSize = (int)Layout->getDataSize().getQuantity(); RC->Layout.HasOwnVFPtr = Layout->hasOwnVFPtr(); RC->Layout.VBPtrOffset = Layout->getVBPtrOffset().getQuantity(); } AccessSpecifierDecl* AccessDecl = nullptr; for(auto it = Record->decls_begin(); it != Record->decls_end(); ++it) { auto D = *it; switch(D->getKind()) { case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: case Decl::CXXMethod: { auto MD = cast(D); auto Method = WalkMethodCXX(MD); Method->AccessDecl = AccessDecl; break; } case Decl::Field: { auto FD = cast(D); auto Field = WalkFieldCXX(FD, RC); if (Layout) Field->Offset = Layout->getFieldOffset(FD->getFieldIndex()); break; } case Decl::AccessSpec: { AccessSpecDecl* AS = cast(D); AccessDecl = new AccessSpecifierDecl(); HandleDeclaration(AS, AccessDecl); AccessDecl->Access = ConvertToAccess(AS->getAccess()); AccessDecl->_Namespace = RC; RC->Specifiers.push_back(AccessDecl); break; } case Decl::IndirectField: // FIXME: Handle indirect fields break; default: { auto Decl = WalkDeclaration(D); break; } } } // Iterate through the record bases. for(auto it = Record->bases_begin(); it != Record->bases_end(); ++it) { clang::CXXBaseSpecifier &BS = *it; BaseClassSpecifier* Base = new BaseClassSpecifier(); Base->Access = ConvertToAccess(BS.getAccessSpecifier()); Base->IsVirtual = BS.isVirtual(); auto BSTL = BS.getTypeSourceInfo()->getTypeLoc(); Base->Type = WalkType(BS.getType(), &BSTL); RC->Bases.push_back(Base); } // Process the vtables if (hasLayout && Record->isDynamicClass()) WalkVTable(Record, RC); } //-----------------------------------// static TemplateSpecializationKind WalkTemplateSpecializationKind(clang::TemplateSpecializationKind Kind) { switch(Kind) { case clang::TSK_Undeclared: return TemplateSpecializationKind::Undeclared; case clang::TSK_ImplicitInstantiation: return TemplateSpecializationKind::ImplicitInstantiation; case clang::TSK_ExplicitSpecialization: return TemplateSpecializationKind::ExplicitSpecialization; case clang::TSK_ExplicitInstantiationDeclaration: return TemplateSpecializationKind::ExplicitInstantiationDeclaration; case clang::TSK_ExplicitInstantiationDefinition: return TemplateSpecializationKind::ExplicitInstantiationDefinition; } llvm_unreachable("Unknown template specialization kind"); } ClassTemplateSpecialization* Parser::WalkClassTemplateSpecialization(clang::ClassTemplateSpecializationDecl* CTS) { auto CT = WalkClassTemplate(CTS->getSpecializedTemplate()); auto Spec = CT->FindSpecialization(CTS); if (Spec != nullptr) return Spec; auto TS = new ClassTemplateSpecialization(); HandleDeclaration(CTS, TS); TS->Name = CTS->getName(); auto NS = GetNamespace(CTS); assert(NS && "Expected a valid namespace"); TS->_Namespace = NS; TS->TemplatedDecl = CT; TS->SpecializationKind = WalkTemplateSpecializationKind(CTS->getSpecializationKind()); CT->Specializations.push_back(TS); // TODO: Parse the template argument list if (CTS->isCompleteDefinition()) WalkRecordCXX(CTS, TS); return TS; } //-----------------------------------// ClassTemplatePartialSpecialization* Parser::WalkClassTemplatePartialSpecialization(clang::ClassTemplatePartialSpecializationDecl* CTS) { auto CT = WalkClassTemplate(CTS->getSpecializedTemplate()); auto Spec = CT->FindPartialSpecialization((void*) CTS); if (Spec != nullptr) return Spec; auto TS = new ClassTemplatePartialSpecialization(); HandleDeclaration(CTS, TS); TS->Name = CTS->getName(); auto NS = GetNamespace(CTS); assert(NS && "Expected a valid namespace"); TS->_Namespace = NS; TS->TemplatedDecl = CT; TS->SpecializationKind = WalkTemplateSpecializationKind(CTS->getSpecializationKind()); CT->Specializations.push_back(TS); // TODO: Parse the template argument list if (CTS->isCompleteDefinition()) WalkRecordCXX(CTS, TS); return TS; } //-----------------------------------// ClassTemplate* Parser::WalkClassTemplate(clang::ClassTemplateDecl* TD) { auto NS = GetNamespace(TD); assert(NS && "Expected a valid namespace"); ClassTemplate* CT = new ClassTemplate(); HandleDeclaration(TD, CT); CT->TemplatedDecl = WalkRecordCXX(TD->getTemplatedDecl()); NS->Templates.push_back(CT); auto TPL = TD->getTemplateParameters(); for(auto it = TPL->begin(); it != TPL->end(); ++it) { auto ND = *it; auto TP = TemplateParameter(); TP.Name = ND->getNameAsString(); CT->Parameters.push_back(TP); } return CT; } //-----------------------------------// static std::vector WalkTemplateParameterList(const clang::TemplateParameterList* TPL) { auto params = std::vector(); for(auto it = TPL->begin(); it != TPL->end(); ++it) { auto ND = *it; auto TP = CppSharp::CppParser::TemplateParameter(); TP.Name = ND->getNameAsString(); params.push_back(TP); } return params; } FunctionTemplate* Parser::WalkFunctionTemplate(clang::FunctionTemplateDecl* TD) { using namespace clang; auto NS = GetNamespace(TD); assert(NS && "Expected a valid namespace"); auto FT = NS->FindFunctionTemplate((void*)TD); if (FT != nullptr) return FT; auto Params = WalkTemplateParameterList(TD->getTemplateParameters()); CppSharp::CppParser::AST::Function* Function = nullptr; auto TemplatedDecl = TD->getTemplatedDecl(); if (auto MD = dyn_cast(TemplatedDecl)) Function = WalkMethodCXX(MD); else Function = WalkFunction(TemplatedDecl, /*IsDependent=*/true, /*AddToNamespace=*/false); auto Name = TD->getNameAsString(); FT = NS->FindFunctionTemplate(Name, Params); if (FT != nullptr && FT->TemplatedDecl == Function) return FT; FT = new FunctionTemplate(); HandleDeclaration(TD, FT); FT->_Namespace = NS; FT->TemplatedDecl = Function; FT->Parameters = Params; NS->Templates.push_back(FT); return FT; } //-----------------------------------// static CXXMethodKind GetMethodKindFromDecl(clang::DeclarationName Name) { using namespace clang; switch(Name.getNameKind()) { case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: return CXXMethodKind::Normal; case DeclarationName::CXXConstructorName: return CXXMethodKind::Constructor; case DeclarationName::CXXDestructorName: return CXXMethodKind::Destructor; case DeclarationName::CXXConversionFunctionName: return CXXMethodKind::Conversion; case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: return CXXMethodKind::Operator; case DeclarationName::CXXUsingDirective: return CXXMethodKind::UsingDirective; } return CXXMethodKind::Normal; } static CXXOperatorKind GetOperatorKindFromDecl(clang::DeclarationName Name) { using namespace clang; if (Name.getNameKind() != DeclarationName::CXXOperatorName) return CXXOperatorKind::None; switch(Name.getCXXOverloadedOperator()) { #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ case OO_##Name: return CXXOperatorKind::Name; #include "clang/Basic/OperatorKinds.def" } return CXXOperatorKind::None; } Method* Parser::WalkMethodCXX(clang::CXXMethodDecl* MD) { using namespace clang; // We could be in a redeclaration, so process the primary context. if (MD->getPrimaryContext() != MD) return WalkMethodCXX(cast(MD->getPrimaryContext())); auto RD = MD->getParent(); auto Decl = WalkDeclaration(RD, /*IgnoreSystemDecls=*/false); auto Class = static_cast(Decl); // Check for an already existing method that came from the same declaration. for (unsigned I = 0, E = Class->Methods.size(); I != E; ++I) { Method* Method = Class->Methods[I]; if (Method->OriginalPtr == MD) return Method; } DeclarationName Name = MD->getDeclName(); Method* Method = new CppSharp::CppParser::Method(); HandleDeclaration(MD, Method); Method->Access = ConvertToAccess(MD->getAccess()); Method->MethodKind = GetMethodKindFromDecl(Name); Method->IsStatic = MD->isStatic(); Method->IsVirtual = MD->isVirtual(); Method->IsConst = MD->isConst(); Method->IsOverride = MD->size_overridden_methods() > 0; WalkFunction(MD, Method); if (const CXXConstructorDecl* CD = dyn_cast(MD)) { Method->IsDefaultConstructor = CD->isDefaultConstructor(); Method->IsCopyConstructor = CD->isCopyConstructor(); Method->IsMoveConstructor = CD->isMoveConstructor(); } else if (const CXXDestructorDecl* DD = dyn_cast(MD)) { } else if (const CXXConversionDecl* CD = dyn_cast(MD)) { auto TL = MD->getTypeSourceInfo()->getTypeLoc().castAs(); auto RTL = TL.getReturnLoc(); auto ConvTy = WalkType(CD->getConversionType(), &RTL); Method->ConversionType = GetQualifiedType(CD->getConversionType(), ConvTy); } Class->Methods.push_back(Method); return Method; } //-----------------------------------// Field* Parser::WalkFieldCXX(clang::FieldDecl* FD, Class* Class) { using namespace clang; Field* F = new Field(); HandleDeclaration(FD, F); F->_Namespace = Class; F->Name = FD->getName(); auto TL = FD->getTypeSourceInfo()->getTypeLoc(); F->QualifiedType = GetQualifiedType(FD->getType(), WalkType(FD->getType(), &TL)); F->Access = ConvertToAccess(FD->getAccess()); F->Class = Class; Class->Fields.push_back(F); return F; } //-----------------------------------// TranslationUnit* Parser::GetTranslationUnit(clang::SourceLocation Loc, SourceLocationKind *Kind) { using namespace clang; SourceManager& SM = C->getSourceManager(); if (Loc.isMacroID()) Loc = SM.getExpansionLoc(Loc); StringRef File; auto LocKind = GetLocationKind(Loc); switch(LocKind) { case SourceLocationKind::Invalid: File = ""; break; case SourceLocationKind::Builtin: File = ""; break; case SourceLocationKind::CommandLine: File = ""; break; default: File = SM.getFilename(Loc); assert(!File.empty() && "Expected to find a valid file"); break; } if (Kind) *Kind = LocKind; auto Unit = Lib->FindOrCreateModule(File); if (Unit->OriginalPtr == nullptr) Unit->OriginalPtr = (void*) SM.getFileEntryForID(SM.getFileID(Loc)); if (LocKind != SourceLocationKind::Invalid) Unit->IsSystemHeader = SM.isInSystemHeader(Loc); return Unit; } //-----------------------------------// TranslationUnit* Parser::GetTranslationUnit(const clang::Decl* D) { clang::SourceLocation Loc = D->getLocation(); SourceLocationKind Kind; TranslationUnit* Unit = GetTranslationUnit(Loc, &Kind); return Unit; } DeclarationContext* Parser::GetNamespace(clang::Decl* D, clang::DeclContext *Ctx) { using namespace clang; // If the declaration is at global scope, just early exit. if (Ctx->isTranslationUnit()) return GetTranslationUnit(D); TranslationUnit* Unit = GetTranslationUnit(cast(Ctx)); // Else we need to do a more expensive check to get all the namespaces, // and then perform a reverse iteration to get the namespaces in order. typedef SmallVector ContextsTy; ContextsTy Contexts; for(; Ctx != nullptr; Ctx = Ctx->getParent()) Contexts.push_back(Ctx); assert(Contexts.back()->isTranslationUnit()); Contexts.pop_back(); DeclarationContext* DC = Unit; for (auto I = Contexts.rbegin(), E = Contexts.rend(); I != E; ++I) { DeclContext* Ctx = *I; switch(Ctx->getDeclKind()) { case Decl::Namespace: { NamespaceDecl* ND = cast(Ctx); if (ND->isAnonymousNamespace()) continue; auto Name = ND->getName(); DC = DC->FindCreateNamespace(Name); HandleDeclaration(ND, DC); continue; } case Decl::LinkageSpec: { const LinkageSpecDecl* LD = cast(Ctx); continue; } case Decl::CXXRecord: { auto RD = cast(Ctx); DC = WalkRecordCXX(RD); continue; } case Decl::ClassTemplateSpecialization: case Decl::ClassTemplatePartialSpecialization: { // FIXME: Ignore ClassTemplateSpecialization namespaces... // We might be able to translate these to C# nested types. continue; } default: { StringRef Kind = Ctx->getDeclKindName(); printf("Unhandled declaration context kind: %s\n", Kind); assert(0 && "Unhandled declaration context kind"); } } } return DC; } DeclarationContext* Parser::GetNamespace(clang::Decl *D) { return GetNamespace(D, D->getDeclContext()); } static PrimitiveType WalkBuiltinType(const clang::BuiltinType* Builtin) { assert(Builtin && "Expected a builtin type"); switch(Builtin->getKind()) { case clang::BuiltinType::Void: return PrimitiveType::Void; case clang::BuiltinType::Bool: return PrimitiveType::Bool; case clang::BuiltinType::SChar: case clang::BuiltinType::Char_S: return PrimitiveType::Int8; case clang::BuiltinType::UChar: case clang::BuiltinType::Char_U: return PrimitiveType::UInt8; case clang::BuiltinType::WChar_S: case clang::BuiltinType::WChar_U: return PrimitiveType::WideChar; case clang::BuiltinType::Short: return PrimitiveType::Int16; case clang::BuiltinType::UShort: return PrimitiveType::UInt16; case clang::BuiltinType::Int: return PrimitiveType::Int32; case clang::BuiltinType::UInt: return PrimitiveType::UInt32; case clang::BuiltinType::Long: return PrimitiveType::Int32; case clang::BuiltinType::ULong: return PrimitiveType::UInt32; case clang::BuiltinType::LongLong: return PrimitiveType::Int64; case clang::BuiltinType::ULongLong: return PrimitiveType::UInt64; case clang::BuiltinType::Float: return PrimitiveType::Float; case clang::BuiltinType::Double: return PrimitiveType::Double; case clang::BuiltinType::NullPtr: return PrimitiveType::Null; default: break; } return PrimitiveType::Null; } //-----------------------------------// clang::TypeLoc ResolveTypeLoc(clang::TypeLoc TL, clang::TypeLoc::TypeLocClass Class) { using namespace clang; auto TypeLocClass = TL.getTypeLocClass(); if (TypeLocClass == Class) { return TL; } if (TypeLocClass == TypeLoc::Qualified) { auto UTL = TL.getUnqualifiedLoc(); TL = UTL; } else if (TypeLocClass == TypeLoc::Elaborated) { auto ETL = TL.getAs(); auto ITL = ETL.getNextTypeLoc(); TL = ITL; } else if (TypeLocClass == TypeLoc::Paren) { auto PTL = TL.getAs(); TL = PTL.getNextTypeLoc(); } assert(TL.getTypeLocClass() == Class); return TL; } static CallingConvention ConvertCallConv(clang::CallingConv CC) { using namespace clang; switch(CC) { case CC_C: return CallingConvention::C; case CC_X86StdCall: return CallingConvention::StdCall; case CC_X86FastCall: return CallingConvention::FastCall; case CC_X86ThisCall: return CallingConvention::ThisCall; case CC_X86Pascal: case CC_AAPCS: case CC_AAPCS_VFP: return CallingConvention::Unknown; } return CallingConvention::Default; } static ParserIntType ConvertIntType(clang::TargetInfo::IntType IT) { switch (IT) { case clang::TargetInfo::IntType::NoInt: return ParserIntType::NoInt; case clang::TargetInfo::IntType::SignedChar: return ParserIntType::SignedChar; case clang::TargetInfo::IntType::UnsignedChar: return ParserIntType::UnsignedChar; case clang::TargetInfo::IntType::SignedShort: return ParserIntType::SignedShort; case clang::TargetInfo::IntType::UnsignedShort: return ParserIntType::UnsignedShort; case clang::TargetInfo::IntType::SignedInt: return ParserIntType::SignedInt; case clang::TargetInfo::IntType::UnsignedInt: return ParserIntType::UnsignedInt; case clang::TargetInfo::IntType::SignedLong: return ParserIntType::SignedLong; case clang::TargetInfo::IntType::UnsignedLong: return ParserIntType::UnsignedLong; case clang::TargetInfo::IntType::SignedLongLong: return ParserIntType::SignedLongLong; case clang::TargetInfo::IntType::UnsignedLongLong: return ParserIntType::UnsignedLongLong; } llvm_unreachable("Unknown parser integer type"); } Type* Parser::WalkType(clang::QualType QualType, clang::TypeLoc* TL, bool DesugarType) { using namespace clang; if (QualType.isNull()) return nullptr; const clang::Type* Type = QualType.getTypePtr(); if (DesugarType) { clang::QualType Desugared = QualType.getDesugaredType(*AST); assert(!Desugared.isNull() && "Expected a valid desugared type"); Type = Desugared.getTypePtr(); } CppSharp::CppParser::AST::Type* Ty = nullptr; assert(Type && "Expected a valid type"); switch(Type->getTypeClass()) { case clang::Type::Attributed: { auto Attributed = Type->getAs(); assert(Attributed && "Expected an attributed type"); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto AT = new AttributedType(); auto Modified = Attributed->getModifiedType(); AT->Modified = GetQualifiedType(Modified, WalkType(Modified, &Next)); auto Equivalent = Attributed->getEquivalentType(); AT->Equivalent = GetQualifiedType(Equivalent, WalkType(Equivalent, &Next)); Ty = AT; break; } case clang::Type::Builtin: { auto Builtin = Type->getAs(); assert(Builtin && "Expected a builtin type"); auto BT = new BuiltinType(); BT->Type = WalkBuiltinType(Builtin); Ty = BT; break; } case clang::Type::Enum: { auto ET = Type->getAs(); EnumDecl* ED = ET->getDecl(); auto TT = new TagType(); TT->Declaration = TT->Declaration = WalkDeclaration(ED, /*IgnoreSystemDecls=*/false); Ty = TT; break; } case clang::Type::Pointer: { auto Pointer = Type->getAs(); auto P = new PointerType(); P->Modifier = PointerType::TypeModifier::Pointer; TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto Pointee = Pointer->getPointeeType(); P->QualifiedPointee = GetQualifiedType(Pointee, WalkType(Pointee, &Next)); Ty = P; break; } case clang::Type::Typedef: { auto TT = Type->getAs(); TypedefNameDecl* TD = TT->getDecl(); auto TTL = TD->getTypeSourceInfo()->getTypeLoc(); auto TDD = static_cast(WalkDeclaration(TD, /*IgnoreSystemDecls=*/false)); auto Type = new TypedefType(); Type->Declaration = TDD; Ty = Type; break; } case clang::Type::Decayed: { auto DT = Type->getAs(); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto Type = new DecayedType(); Type->Decayed = GetQualifiedType(DT->getDecayedType(), WalkType(DT->getDecayedType(), &Next)); Type->Original = GetQualifiedType(DT->getOriginalType(), WalkType(DT->getOriginalType(), &Next)); Type->Pointee = GetQualifiedType(DT->getPointeeType(), WalkType(DT->getPointeeType(), &Next)); Ty = Type; break; } case clang::Type::Elaborated: { auto ET = Type->getAs(); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); Ty = WalkType(ET->getNamedType(), &Next); break; } case clang::Type::Record: { auto RT = Type->getAs(); RecordDecl* RD = RT->getDecl(); auto TT = new TagType(); TT->Declaration = WalkDeclaration(RD, /*IgnoreSystemDecls=*/false); Ty = TT; break; } case clang::Type::Paren: { auto PT = Type->getAs(); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); Ty = WalkType(PT->getInnerType(), &Next); break; } case clang::Type::ConstantArray: { auto AT = AST->getAsConstantArrayType(QualType); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto A = new ArrayType(); A->QualifiedType = GetQualifiedType(AT->getElementType(), WalkType(AT->getElementType(), &Next)); A->SizeType = ArrayType::ArraySize::Constant; A->Size = AST->getConstantArrayElementCount(AT); Ty = A; break; } case clang::Type::IncompleteArray: { auto AT = AST->getAsIncompleteArrayType(QualType); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto A = new ArrayType(); A->QualifiedType = GetQualifiedType(AT->getElementType(), WalkType(AT->getElementType(), &Next)); A->SizeType = ArrayType::ArraySize::Incomplete; Ty = A; break; } case clang::Type::DependentSizedArray: { auto AT = AST->getAsDependentSizedArrayType(QualType); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto A = new ArrayType(); A->QualifiedType = GetQualifiedType(AT->getElementType(), WalkType(AT->getElementType(), &Next)); A->SizeType = ArrayType::ArraySize::Dependent; //A->Size = AT->getSizeExpr(); Ty = A; break; } case clang::Type::FunctionProto: { auto FP = Type->getAs(); FunctionProtoTypeLoc FTL; TypeLoc RL; if (TL && !TL->isNull()) { FTL = TL->getAs(); RL = FTL.getReturnLoc(); } auto F = new FunctionType(); F->ReturnType = GetQualifiedType(FP->getReturnType(), WalkType(FP->getReturnType(), &RL)); F->CallingConvention = ConvertCallConv(FP->getCallConv()); for (unsigned i = 0; i < FP->getNumParams(); ++i) { auto FA = new Parameter(); if (FTL) { auto PVD = FTL.getParam(i); HandleDeclaration(PVD, FA); auto PTL = PVD->getTypeSourceInfo()->getTypeLoc(); FA->Name = PVD->getNameAsString(); FA->QualifiedType = GetQualifiedType(PVD->getType(), WalkType(PVD->getType(), &PTL)); } else { auto Arg = FP->getParamType(i); FA->Name = ""; FA->QualifiedType = GetQualifiedType(Arg, WalkType(Arg)); } F->Parameters.push_back(FA); } return F; Ty = F; break; } case clang::Type::TypeOf: { auto TO = Type->getAs(); Ty = WalkType(TO->getUnderlyingType()); break; } case clang::Type::TypeOfExpr: { auto TO = Type->getAs(); Ty = WalkType(TO->getUnderlyingExpr()->getType()); break; } case clang::Type::MemberPointer: { auto MP = Type->getAs(); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto MPT = new MemberPointerType(); MPT->Pointee = GetQualifiedType(MP->getPointeeType(), WalkType(MP->getPointeeType(), &Next)); Ty = MPT; break; } case clang::Type::TemplateSpecialization: { auto TS = Type->getAs(); auto TST = new TemplateSpecializationType(); TemplateName Name = TS->getTemplateName(); TST->Template = static_cast(WalkDeclaration( Name.getAsTemplateDecl(), 0, /*IgnoreSystemDecls=*/false)); if (TS->isSugared()) TST->Desugared = WalkType(TS->desugar()); auto TypeLocClass = TL->getTypeLocClass(); if (TypeLocClass == TypeLoc::Qualified) { auto UTL = TL->getUnqualifiedLoc(); TL = &UTL; } else if (TypeLocClass == TypeLoc::Elaborated) { auto ETL = TL->getAs(); auto ITL = ETL.getNextTypeLoc(); TL = &ITL; } assert(TL->getTypeLocClass() == TypeLoc::TemplateSpecialization); auto TSTL = TL->getAs(); for (unsigned I = 0, E = TS->getNumArgs(); I != E; ++I) { const clang::TemplateArgument& TA = TS->getArg(I); auto Arg = TemplateArgument(); TemplateArgumentLoc ArgLoc; ArgLoc = TSTL.getArgLoc(I); switch(TA.getKind()) { case clang::TemplateArgument::Type: { Arg.Kind = TemplateArgument::ArgumentKind::Type; TypeLoc ArgTL; ArgTL = ArgLoc.getTypeSourceInfo()->getTypeLoc(); Arg.Type = GetQualifiedType(TA.getAsType(), WalkType(TA.getAsType(), &ArgTL)); break; } case clang::TemplateArgument::Declaration: Arg.Kind = TemplateArgument::ArgumentKind::Declaration; Arg.Declaration = WalkDeclaration(TA.getAsDecl(), 0); break; case clang::TemplateArgument::NullPtr: Arg.Kind = TemplateArgument::ArgumentKind::NullPtr; break; case clang::TemplateArgument::Integral: Arg.Kind = TemplateArgument::ArgumentKind::Integral; //Arg.Type = WalkType(TA.getIntegralType(), 0); Arg.Integral = TA.getAsIntegral().getLimitedValue(); break; case clang::TemplateArgument::Template: Arg.Kind = TemplateArgument::ArgumentKind::Template; break; case clang::TemplateArgument::TemplateExpansion: Arg.Kind = TemplateArgument::ArgumentKind::TemplateExpansion; break; case clang::TemplateArgument::Expression: Arg.Kind = TemplateArgument::ArgumentKind::Expression; break; case clang::TemplateArgument::Pack: Arg.Kind = TemplateArgument::ArgumentKind::Pack; break; } TST->Arguments.push_back(Arg); } Ty = TST; break; } case clang::Type::TemplateTypeParm: { auto TP = Type->getAs(); auto TPT = new TemplateParameterType(); if (auto Ident = TP->getIdentifier()) TPT->Parameter.Name = Ident->getName(); Ty = TPT; break; } case clang::Type::SubstTemplateTypeParm: { auto TP = Type->getAs(); auto TPT = new TemplateParameterSubstitutionType(); TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto RepTy = TP->getReplacementType(); TPT->Replacement = GetQualifiedType(RepTy, WalkType(RepTy, &Next)); Ty = TPT; break; } case clang::Type::InjectedClassName: { auto ICN = Type->getAs(); auto ICNT = new InjectedClassNameType(); ICNT->Class = static_cast(WalkDeclaration( ICN->getDecl(), 0, /*IgnoreSystemDecls=*/false)); Ty = ICNT; break; } case clang::Type::DependentName: { auto DN = Type->getAs(); auto DNT = new DependentNameType(); Ty = DNT; break; } case clang::Type::LValueReference: { auto LR = Type->getAs(); auto P = new PointerType(); P->Modifier = PointerType::TypeModifier::LVReference; TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto Pointee = LR->getPointeeType(); P->QualifiedPointee = GetQualifiedType(Pointee, WalkType(Pointee, &Next)); Ty = P; break; } case clang::Type::RValueReference: { auto LR = Type->getAs(); auto P = new PointerType(); P->Modifier = PointerType::TypeModifier::RVReference; TypeLoc Next; if (TL && !TL->isNull()) Next = TL->getNextTypeLoc(); auto Pointee = LR->getPointeeType(); P->QualifiedPointee = GetQualifiedType(Pointee, WalkType(Pointee, &Next)); Ty = P; break; } case clang::Type::Vector: { // GCC-specific / __attribute__((vector_size(n)) return nullptr; } case clang::Type::PackExpansion: { // TODO: stubbed Ty = new PackExpansionType(); } default: { Debug("Unhandled type class '%s'\n", Type->getTypeClassName()); return nullptr; } } Ty->IsDependent = Type->isDependentType(); return Ty; } //-----------------------------------// Enumeration* Parser::WalkEnum(clang::EnumDecl* ED) { auto NS = GetNamespace(ED); assert(NS && "Expected a valid namespace"); auto Name = GetTagDeclName(ED); auto E = NS->FindEnum(Name, /*Create=*/false); if (E && !E->IsIncomplete) return E; if (!E) { E = NS->FindEnum(Name, /*Create=*/true); HandleDeclaration(ED, E); } if (ED->isScoped()) E->Modifiers = (Enumeration::EnumModifiers) ((int)E->Modifiers | (int)Enumeration::EnumModifiers::Scoped); // Get the underlying integer backing the enum. clang::QualType IntType = ED->getIntegerType(); E->Type = WalkType(IntType, 0); E->BuiltinType = static_cast(WalkType(IntType, 0, /*DesugarType=*/true)); if (!ED->isThisDeclarationADefinition()) { E->IsIncomplete = true; return E; } E->IsIncomplete = false; for(auto it = ED->enumerator_begin(); it != ED->enumerator_end(); ++it) { clang::EnumConstantDecl* ECD = (*it); auto EnumItem = Enumeration::Item(); HandleDeclaration(ECD, &EnumItem); EnumItem.Name = ECD->getNameAsString(); auto Value = ECD->getInitVal(); EnumItem.Value = Value.isSigned() ? Value.getSExtValue() : Value.getZExtValue(); std::string Text; if (GetDeclText(ECD->getSourceRange(), Text)) EnumItem.Expression = Text; E->Items.push_back(EnumItem); } return E; } //-----------------------------------// static const clang::CodeGen::CGFunctionInfo& GetCodeGenFuntionInfo( clang::CodeGen::CodeGenTypes* CodeGenTypes, clang::FunctionDecl* FD) { using namespace clang; if (auto CD = dyn_cast(FD)) { return CodeGenTypes->arrangeCXXConstructorDeclaration(CD, Ctor_Base); } else if (auto DD = dyn_cast(FD)) { return CodeGenTypes->arrangeCXXDestructor(DD, Dtor_Base); } return CodeGenTypes->arrangeFunctionDeclaration(FD); } static bool CanCheckCodeGenInfo(clang::Sema& S, const clang::Type* Ty, bool IsMicrosoftABI) { bool CheckCodeGenInfo = true; if (auto RT = Ty->getAs()) CheckCodeGenInfo &= RT->getDecl()->getDefinition() != 0; if (auto RD = Ty->getAsCXXRecordDecl()) CheckCodeGenInfo &= RD->hasDefinition(); // Lock in the MS inheritance model if we have a member pointer to a class, // else we get an assertion error inside Clang's codegen machinery. if (IsMicrosoftABI) { if (auto MPT = Ty->getAs()) if (!MPT->isDependentType()) S.RequireCompleteType(clang::SourceLocation(), clang::QualType(Ty, 0), 0); } return CheckCodeGenInfo; } void Parser::WalkFunction(clang::FunctionDecl* FD, Function* F, bool IsDependent) { using namespace clang; assert (FD->getBuiltinID() == 0); auto FT = FD->getType()->getAs(); auto NS = GetNamespace(FD); assert(NS && "Expected a valid namespace"); F->OriginalPtr = (void*) FD; F->Name = FD->getNameAsString(); F->_Namespace = NS; F->IsVariadic = FD->isVariadic(); F->IsInline = FD->isInlined(); F->IsDependent = FD->isDependentContext(); F->IsPure = FD->isPure(); F->IsDeleted = FD->isDeleted(); auto CC = FT->getCallConv(); F->CallingConvention = ConvertCallConv(CC); F->OperatorKind = GetOperatorKindFromDecl(FD->getDeclName()); TypeLoc RTL; if (auto TSI = FD->getTypeSourceInfo()) { FunctionTypeLoc FTL = TSI->getTypeLoc().getAs(); if (FTL) { RTL = FTL.getReturnLoc(); auto &SM = C->getSourceManager(); auto headStartLoc = GetDeclStartLocation(C.get(), FD); auto headEndLoc = SM.getExpansionLoc(FTL.getLParenLoc()); auto headRange = clang::SourceRange(headStartLoc, headEndLoc); HandlePreprocessedEntities(F, headRange, MacroLocation::FunctionHead); HandlePreprocessedEntities(F, FTL.getParensRange(), MacroLocation::FunctionParameters); //auto bodyRange = clang::SourceRange(FTL.getRParenLoc(), FD->getLocEnd()); //HandlePreprocessedEntities(F, bodyRange, MacroLocation::FunctionBody); } } F->ReturnType = GetQualifiedType(FD->getReturnType(), WalkType(FD->getReturnType(), &RTL)); String Mangled = GetDeclMangledName(FD, TargetABI, IsDependent); F->Mangled = Mangled; SourceLocation ParamStartLoc = FD->getLocStart(); SourceLocation ResultLoc; auto FTSI = FD->getTypeSourceInfo(); if (FTSI) { auto FTL = FTSI->getTypeLoc(); while (FTL && !FTL.getAs()) FTL = FTL.getNextTypeLoc(); if (FTL) { auto FTInfo = FTL.castAs(); assert (!FTInfo.isNull()); ParamStartLoc = FTInfo.getRParenLoc(); ResultLoc = FTInfo.getReturnLoc().getLocStart(); } } clang::SourceRange Range(FD->getLocStart(), ParamStartLoc); if (ResultLoc.isValid()) Range.setBegin(ResultLoc); std::string Sig; if (GetDeclText(Range, Sig)) F->Signature = Sig; for(auto it = FD->param_begin(); it != FD->param_end(); ++it) { ParmVarDecl* VD = (*it); auto P = new Parameter(); P->Name = VD->getNameAsString(); TypeLoc PTL; if (auto TSI = VD->getTypeSourceInfo()) PTL = VD->getTypeSourceInfo()->getTypeLoc(); auto paramRange = VD->getSourceRange(); paramRange.setBegin(ParamStartLoc); HandlePreprocessedEntities(P, paramRange, MacroLocation::FunctionParameters); P->QualifiedType = GetQualifiedType(VD->getType(), WalkType(VD->getType(), &PTL)); P->HasDefaultValue = VD->hasDefaultArg(); P->_Namespace = NS; HandleDeclaration(VD, P); F->Parameters.push_back(P); ParamStartLoc = VD->getLocEnd(); } bool IsMicrosoftABI = C->getASTContext().getTargetInfo().getCXXABI().isMicrosoft(); bool CheckCodeGenInfo = !FD->isDependentContext() && !FD->isInvalidDecl(); CheckCodeGenInfo &= CanCheckCodeGenInfo(C->getSema(), FD->getReturnType().getTypePtr(), IsMicrosoftABI); for (auto I = FD->param_begin(), E = FD->param_end(); I != E; ++I) CheckCodeGenInfo &= CanCheckCodeGenInfo(C->getSema(), (*I)->getType().getTypePtr(), IsMicrosoftABI); if (CheckCodeGenInfo) { auto& CGInfo = GetCodeGenFuntionInfo(CodeGenTypes, FD); F->IsReturnIndirect = CGInfo.getReturnInfo().isIndirect(); unsigned Index = 0; for (auto I = CGInfo.arg_begin(), E = CGInfo.arg_end(); I != E; I++) { // Skip the first argument as it's the return type. if (I == CGInfo.arg_begin()) continue; if (Index >= F->Parameters.size()) continue; F->Parameters[Index++]->IsIndirect = I->info.isIndirect(); } } } Function* Parser::WalkFunction(clang::FunctionDecl* FD, bool IsDependent, bool AddToNamespace) { using namespace clang; assert (FD->getBuiltinID() == 0); auto NS = GetNamespace(FD); assert(NS && "Expected a valid namespace"); auto Name = FD->getNameAsString(); Function* F = NS->FindFunction(Name, /*Create=*/ false); if (F != nullptr) return F; F = new Function(); HandleDeclaration(FD, F); WalkFunction(FD, F, IsDependent); if (AddToNamespace) NS->Functions.push_back(F); return F; } //-----------------------------------// SourceLocationKind Parser::GetLocationKind(const clang::SourceLocation& Loc) { using namespace clang; SourceManager& SM = C->getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc); if(PLoc.isInvalid()) return SourceLocationKind::Invalid; const char *FileName = PLoc.getFilename(); if(strcmp(FileName, "") == 0) return SourceLocationKind::Builtin; if(strcmp(FileName, "") == 0) return SourceLocationKind::CommandLine; if(SM.getFileCharacteristic(Loc) == clang::SrcMgr::C_User) return SourceLocationKind::User; return SourceLocationKind::System; } bool Parser::IsValidDeclaration(const clang::SourceLocation& Loc) { auto Kind = GetLocationKind(Loc); return Kind == SourceLocationKind::User; } //-----------------------------------// void Parser::WalkAST() { auto TU = AST->getTranslationUnitDecl(); for(auto it = TU->decls_begin(); it != TU->decls_end(); ++it) { clang::Decl* D = (*it); WalkDeclarationDef(D); } } //-----------------------------------// Variable* Parser::WalkVariable(clang::VarDecl *VD) { using namespace clang; auto Var = new Variable(); HandleDeclaration(VD, Var); Var->Name = VD->getName(); Var->Access = ConvertToAccess(VD->getAccess()); auto TL = VD->getTypeSourceInfo()->getTypeLoc(); Var->QualifiedType = GetQualifiedType(VD->getType(), WalkType(VD->getType(), &TL)); auto Mangled = GetDeclMangledName(VD, TargetABI, /*IsDependent=*/false); Var->Mangled = Mangled; return Var; } //-----------------------------------// bool Parser::GetDeclText(clang::SourceRange SR, std::string& Text) { using namespace clang; SourceManager& SM = C->getSourceManager(); const LangOptions &LangOpts = C->getLangOpts(); auto Range = CharSourceRange::getTokenRange(SR); bool Invalid; Text = Lexer::getSourceText(Range, SM, LangOpts, &Invalid); return !Invalid && !Text.empty(); } PreprocessedEntity* Parser::WalkPreprocessedEntity( Declaration* Decl, clang::PreprocessedEntity* PPEntity) { using namespace clang; for (unsigned I = 0, E = Decl->PreprocessedEntities.size(); I != E; ++I) { auto Entity = Decl->PreprocessedEntities[I]; if (Entity->OriginalPtr == PPEntity) return Entity; } auto& P = C->getPreprocessor(); PreprocessedEntity* Entity = 0; switch(PPEntity->getKind()) { case clang::PreprocessedEntity::MacroExpansionKind: { auto MD = cast(PPEntity); Entity = new MacroExpansion(); std::string Text; if (!GetDeclText(PPEntity->getSourceRange(), Text)) return nullptr; static_cast(Entity)->Text = Text; break; } case clang::PreprocessedEntity::MacroDefinitionKind: { auto MD = cast(PPEntity); if (!IsValidDeclaration(MD->getLocation())) break; const IdentifierInfo* II = MD->getName(); assert(II && "Expected valid identifier info"); MacroInfo* MI = P.getMacroInfo((IdentifierInfo*)II); if (!MI || MI->isBuiltinMacro() || MI->isFunctionLike()) break; SourceManager& SM = C->getSourceManager(); const LangOptions &LangOpts = C->getLangOpts(); auto Loc = MI->getDefinitionLoc(); if (!IsValidDeclaration(Loc)) break; SourceLocation BeginExpr = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); auto Range = CharSourceRange::getTokenRange( BeginExpr, MI->getDefinitionEndLoc()); bool Invalid; StringRef Expression = Lexer::getSourceText(Range, SM, LangOpts, &Invalid); if (Invalid || Expression.empty()) break; auto Definition = new MacroDefinition(); Entity = Definition; Definition->_Namespace = GetTranslationUnit(MD->getLocation(), NULL); Definition->Name = II->getName().trim(); Definition->Expression = Expression.trim(); } } if (!Entity) return nullptr; Entity->OriginalPtr = PPEntity; Decl->PreprocessedEntities.push_back(Entity); return Entity; } void Parser::HandlePreprocessedEntities(Declaration* Decl) { using namespace clang; auto PPRecord = C->getPreprocessor().getPreprocessingRecord(); for (auto it = PPRecord->begin(); it != PPRecord->end(); ++it) { clang::PreprocessedEntity* PPEntity = (*it); auto Entity = WalkPreprocessedEntity(Decl, PPEntity); } } void Parser::HandlePreprocessedEntities(Declaration* Decl, clang::SourceRange sourceRange, MacroLocation macroLocation) { if (sourceRange.isInvalid()) return; auto& SourceMgr = C->getSourceManager(); auto isBefore = SourceMgr.isBeforeInTranslationUnit(sourceRange.getEnd(), sourceRange.getBegin()); if (isBefore) return; assert(!SourceMgr.isBeforeInTranslationUnit(sourceRange.getEnd(), sourceRange.getBegin())); using namespace clang; auto PPRecord = C->getPreprocessor().getPreprocessingRecord(); auto Range = PPRecord->getPreprocessedEntitiesInRange(sourceRange); for (auto it = Range.first; it != Range.second; ++it) { auto PPEntity = (*it); auto Entity = WalkPreprocessedEntity(Decl, PPEntity); if (!Entity) continue; if (Entity->Location == MacroLocation::Unknown) Entity->Location = macroLocation; } } void Parser::HandleOriginalText(clang::Decl* D, Declaration* Decl) { auto &SM = C->getSourceManager(); auto &LangOpts = C->getLangOpts(); auto Range = clang::CharSourceRange::getTokenRange(D->getSourceRange()); bool Invalid; auto DeclText = clang::Lexer::getSourceText(Range, SM, LangOpts, &Invalid); if (!Invalid) Decl->DebugText = DeclText; } void Parser::HandleDeclaration(clang::Decl* D, Declaration* Decl) { if (Decl->OriginalPtr != nullptr) return; Decl->OriginalPtr = (void*) D; if (Decl->PreprocessedEntities.empty() && !D->isImplicit()) { if (clang::dyn_cast(D)) { HandlePreprocessedEntities(Decl); } else if (clang::dyn_cast(D)) { // Ignore function parameters as we already walk their preprocessed entities. } else { auto startLoc = GetDeclStartLocation(C.get(), D); auto endLoc = D->getLocEnd(); auto range = clang::SourceRange(startLoc, endLoc); HandlePreprocessedEntities(Decl, range); } } HandleOriginalText(D, Decl); HandleComments(D, Decl); if (const clang::ValueDecl *VD = clang::dyn_cast_or_null(D)) Decl->IsDependent = VD->getType()->isDependentType(); if (const clang::DeclContext *DC = clang::dyn_cast_or_null(D)) Decl->IsDependent |= DC->isDependentContext(); Decl->Access = ConvertToAccess(D->getAccess()); } //-----------------------------------// Declaration* Parser::WalkDeclarationDef(clang::Decl* D) { return WalkDeclaration(D, /*IgnoreSystemDecls=*/true, /*CanBeDefinition=*/true); } Declaration* Parser::WalkDeclaration(clang::Decl* D, bool IgnoreSystemDecls, bool CanBeDefinition) { using namespace clang; // Ignore declarations that do not come from user-provided // header files. if (IgnoreSystemDecls && !IsValidDeclaration(D->getLocation())) return nullptr; for(auto it = D->attr_begin(); it != D->attr_end(); ++it) { Attr* Attr = (*it); if(Attr->getKind() != clang::attr::Annotate) continue; AnnotateAttr* Annotation = cast(Attr); assert(Annotation != nullptr); StringRef AnnotationText = Annotation->getAnnotation(); } Declaration* Decl = nullptr; auto Kind = D->getKind(); switch(D->getKind()) { case Decl::CXXRecord: { CXXRecordDecl* RD = cast(D); auto Class = WalkRecordCXX(RD); // We store a definition order index into the declarations. // This is needed because declarations are added to their contexts as // soon as they are referenced and we need to know the original order // of the declarations. if (CanBeDefinition && Class->DefinitionOrder == 0) { Class->DefinitionOrder = Index++; //Debug("%d: %s\n", Index++, GetTagDeclName(RD).c_str()); } Decl = Class; break; } case Decl::ClassTemplate: { ClassTemplateDecl* TD = cast(D); auto Template = WalkClassTemplate(TD); auto NS = GetNamespace(TD); Template->_Namespace = NS; NS->Templates.push_back(Template); Decl = Template; break; } case Decl::ClassTemplateSpecialization: { auto TS = cast(D); auto CT = new ClassTemplateSpecialization(); HandleDeclaration(TS, CT); Decl = CT; break; } case Decl::ClassTemplatePartialSpecialization: { auto TS = cast(D); auto CT = new ClassTemplatePartialSpecialization(); HandleDeclaration(TS, CT); Decl = CT; break; } case Decl::FunctionTemplate: { FunctionTemplateDecl* TD = cast(D); auto Template = WalkFunctionTemplate(TD); auto NS = GetNamespace(TD); Template->_Namespace = NS; NS->Templates.push_back(Template); Decl = Template; break; } case Decl::Enum: { EnumDecl* ED = cast(D); Decl = WalkEnum(ED); break; } case Decl::Function: { FunctionDecl* FD = cast(D); if (!FD->isFirstDecl()) break; // Check for and ignore built-in functions. if (FD->getBuiltinID() != 0) break; Decl = WalkFunction(FD); break; } case Decl::LinkageSpec: { LinkageSpecDecl* LS = cast(D); for (auto it = LS->decls_begin(); it != LS->decls_end(); ++it) { clang::Decl* D = (*it); Decl = WalkDeclarationDef(D); } break; } case Decl::Typedef: { auto TD = cast(D); auto NS = GetNamespace(TD); auto Name = GetDeclName(TD); auto Typedef = NS->FindTypedef(Name, /*Create=*/false); if (Typedef) return Typedef; Typedef = NS->FindTypedef(Name, /*Create=*/true); HandleDeclaration(TD, Typedef); auto TTL = TD->getTypeSourceInfo()->getTypeLoc(); Typedef->QualifiedType = GetQualifiedType(TD->getUnderlyingType(), WalkType(TD->getUnderlyingType(), &TTL)); Decl = Typedef; break; } case Decl::Namespace: { NamespaceDecl* ND = cast(D); for (auto it = ND->decls_begin(); it != ND->decls_end(); ++it) { clang::Decl* D = (*it); Decl = WalkDeclarationDef(D); } break; } case Decl::Var: { auto VD = cast(D); Decl = WalkVariable(VD); auto NS = GetNamespace(VD); Decl->_Namespace = NS; NS->Variables.push_back(static_cast(Decl)); break; } // Ignore these declarations since they must have been declared in // a class already. case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: case Decl::CXXMethod: break; case Decl::Empty: case Decl::AccessSpec: case Decl::Friend: case Decl::Using: case Decl::UsingDirective: case Decl::UsingShadow: case Decl::UnresolvedUsingTypename: case Decl::UnresolvedUsingValue: case Decl::IndirectField: case Decl::StaticAssert: break; default: { Debug("Unhandled declaration kind: %s\n", D->getDeclKindName()); auto &SM = C->getSourceManager(); auto Loc = D->getLocation(); auto FileName = SM.getFilename(Loc); auto Offset = SM.getFileOffset(Loc); auto LineNo = SM.getLineNumber(SM.getFileID(Loc), Offset); Debug(" %s (line %u)\n", FileName, LineNo); break; } }; return Decl; } //-----------------------------------// struct Diagnostic { clang::SourceLocation Location; llvm::SmallString<100> Message; clang::DiagnosticsEngine::Level Level; }; struct DiagnosticConsumer : public clang::DiagnosticConsumer { virtual ~DiagnosticConsumer() { } virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level Level, const clang::Diagnostic& Info) override { // Update the base type NumWarnings and NumErrors variables. if (Level == clang::DiagnosticsEngine::Warning) NumWarnings++; if (Level == clang::DiagnosticsEngine::Error || Level == clang::DiagnosticsEngine::Fatal) NumErrors++; auto Diag = Diagnostic(); Diag.Location = Info.getLocation(); Diag.Level = Level; Info.FormatDiagnostic(Diag.Message); Diagnostics.push_back(Diag); } std::vector Diagnostics; }; void Parser::HandleDiagnostics(ParserResult* res) { auto DiagClient = (DiagnosticConsumer&) C->getDiagnosticClient(); auto &Diags = DiagClient.Diagnostics; // Convert the diagnostics to the managed types for (unsigned I = 0, E = Diags.size(); I != E; ++I) { auto& Diag = DiagClient.Diagnostics[I]; auto& Source = C->getSourceManager(); auto FileName = Source.getFilename(Source.getFileLoc(Diag.Location)); auto PDiag = ParserDiagnostic(); PDiag.FileName = FileName.str(); PDiag.Message = Diag.Message.str(); PDiag.LineNumber = 0; PDiag.ColumnNumber = 0; if( !Diag.Location.isInvalid() ) { clang::PresumedLoc PLoc = Source.getPresumedLoc(Diag.Location); if( PLoc.isValid() ) { PDiag.LineNumber = PLoc.getLine(); PDiag.ColumnNumber = PLoc.getColumn(); } } switch( Diag.Level ) { case clang::DiagnosticsEngine::Ignored: PDiag.Level = ParserDiagnosticLevel::Ignored; break; case clang::DiagnosticsEngine::Note: PDiag.Level = ParserDiagnosticLevel::Note; break; case clang::DiagnosticsEngine::Warning: PDiag.Level = ParserDiagnosticLevel::Warning; break; case clang::DiagnosticsEngine::Error: PDiag.Level = ParserDiagnosticLevel::Error; break; case clang::DiagnosticsEngine::Fatal: PDiag.Level = ParserDiagnosticLevel::Fatal; break; default: assert(0); } res->Diagnostics.push_back(PDiag); } } ParserResult* Parser::ParseHeader(const std::string& File) { assert(Opts->ASTContext && "Expected a valid ASTContext"); auto res = new ParserResult(); res->ASTContext = Lib; if (File.empty()) { res->Kind = ParserResultKind::FileNotFound; return res; } SetupHeader(); auto SC = new clang::SemaConsumer(); C->setASTConsumer(SC); C->createSema(clang::TU_Complete, 0); SC->InitializeSema(C->getSema()); auto DiagClient = new DiagnosticConsumer(); C->getDiagnostics().setClient(DiagClient); // Check that the file is reachable. const clang::DirectoryLookup *Dir; llvm::SmallVector Includers; auto FileEntry = C->getPreprocessor().getHeaderSearchInfo().LookupFile(File, clang::SourceLocation(), /*isAngled*/true, nullptr, Dir, Includers, nullptr, nullptr, nullptr); if (!FileEntry) { res->Kind = ParserResultKind::FileNotFound; return res; } // Create a virtual file that includes the header. This gets rid of some // Clang warnings about parsing an header file as the main file. std::string str; str += "#include \"" + File + "\"" + "\n"; str += "\0"; auto buffer = llvm::MemoryBuffer::getMemBuffer(str); C->getSourceManager().createMainFileIDForMemBuffer(buffer); clang::DiagnosticConsumer* client = C->getDiagnostics().getClient(); client->BeginSourceFile(C->getLangOpts(), &C->getPreprocessor()); ParseAST(C->getSema(), /*PrintStats=*/false, /*SkipFunctionBodies=*/true); client->EndSourceFile(); HandleDiagnostics(res); if(client->getNumErrors() != 0) { res->Kind = ParserResultKind::Error; return res; } AST = &C->getASTContext(); auto FileName = FileEntry->getName(); auto Unit = Lib->FindOrCreateModule(FileName); auto TU = AST->getTranslationUnitDecl(); HandleDeclaration(TU, Unit); if (Unit->OriginalPtr == nullptr) Unit->OriginalPtr = (void*) FileEntry; // Initialize enough Clang codegen machinery so we can get at ABI details. llvm::LLVMContext Ctx; llvm::OwningPtr M(new llvm::Module("", Ctx)); M->setTargetTriple(AST->getTargetInfo().getTriple().getTriple()); M->setDataLayout(AST->getTargetInfo().getTargetDescription()); llvm::OwningPtr TD(new llvm::DataLayout(AST->getTargetInfo() .getTargetDescription())); llvm::OwningPtr CGM( new clang::CodeGen::CodeGenModule(C->getASTContext(), C->getCodeGenOpts(), *M, *TD, C->getDiagnostics())); llvm::OwningPtr CGT( new clang::CodeGen::CodeGenTypes(*CGM.get())); CodeGenInfo = (clang::TargetCodeGenInfo*) &CGM->getTargetCodeGenInfo(); CodeGenTypes = CGT.get(); WalkAST(); res->Kind = ParserResultKind::Success; return res; } ParserResultKind Parser::ParseArchive(llvm::StringRef File, llvm::MemoryBuffer *Buffer, CppSharp::CppParser::NativeLibrary*& NativeLib) { llvm::error_code Code; llvm::object::Archive Archive(Buffer, Code); if (Code) return ParserResultKind::Error; auto LibName = File; NativeLib = new NativeLibrary(); NativeLib->FileName = LibName; for(auto it = Archive.symbol_begin(); it != Archive.symbol_end(); ++it) { llvm::StringRef SymRef; if (it->getName(SymRef)) continue; NativeLib->Symbols.push_back(SymRef); } return ParserResultKind::Success; } ParserResultKind Parser::ParseSharedLib(llvm::StringRef File, llvm::MemoryBuffer *Buffer, CppSharp::CppParser::NativeLibrary*& NativeLib) { auto Object = llvm::object::ObjectFile::createObjectFile(Buffer); if (!Object) return ParserResultKind::Error; auto LibName = File; NativeLib = new NativeLibrary(); NativeLib->FileName = LibName; llvm::error_code ec; for(auto it = Object.get()->symbol_begin(); it != Object.get()->symbol_end(); ++it) { std::string Sym; llvm::raw_string_ostream SymStream(Sym); if (it->printName(SymStream)) continue; NativeLib->Symbols.push_back(Sym); } for (auto it = Object.get()->symbol_begin(); it != Object.get()->symbol_end(); ++it) { std::string Sym; llvm::raw_string_ostream SymStream(Sym); if (it->printName(SymStream)) continue; NativeLib->Symbols.push_back(Sym); } return ParserResultKind::Success; } ParserResult* Parser::ParseLibrary(const std::string& File) { auto res = new ParserResult(); res->ASTContext = Lib; if (File.empty()) { res->Kind = ParserResultKind::FileNotFound; return res; } C.reset(new clang::CompilerInstance()); C->createFileManager(); auto &FM = C->getFileManager(); const clang::FileEntry* FileEntry = 0; for (unsigned I = 0, E = Opts->LibraryDirs.size(); I != E; ++I) { auto& LibDir = Opts->LibraryDirs[I]; llvm::SmallString<256> Path(LibDir); llvm::sys::path::append(Path, File); if ((FileEntry = FM.getFile(Path.str()))) break; } if (!FileEntry) { res->Kind = ParserResultKind::FileNotFound; return res; } res->Kind = ParseArchive(File, FM.getBufferForFile(FileEntry), res->Library); if (res->Kind == ParserResultKind::Success) return res; res->Kind = ParseSharedLib(File, FM.getBufferForFile(FileEntry), res->Library); if (res->Kind == ParserResultKind::Success) return res; return res; } ParserResult* ClangParser::ParseHeader(ParserOptions* Opts) { if (!Opts) return nullptr; Parser parser(Opts); return parser.ParseHeader(Opts->FileName); } ParserResult* ClangParser::ParseLibrary(ParserOptions* Opts) { if (!Opts) return nullptr; Parser parser(Opts); return parser.ParseLibrary(Opts->FileName); } ParserTargetInfo* Parser::GetTargetInfo() { assert(Opts->ASTContext && "Expected a valid ASTContext"); auto res = new ParserResult(); res->ASTContext = Lib; SetupHeader(); auto SC = new clang::SemaConsumer(); C->setASTConsumer(SC); C->createSema(clang::TU_Complete, 0); SC->InitializeSema(C->getSema()); auto DiagClient = new DiagnosticConsumer(); C->getDiagnostics().setClient(DiagClient); AST = &C->getASTContext(); // Initialize enough Clang codegen machinery so we can get at ABI details. llvm::LLVMContext Ctx; llvm::OwningPtr M(new llvm::Module("", Ctx)); M->setTargetTriple(AST->getTargetInfo().getTriple().getTriple()); M->setDataLayout(AST->getTargetInfo().getTargetDescription()); llvm::OwningPtr TD(new llvm::DataLayout(AST->getTargetInfo() .getTargetDescription())); llvm::OwningPtr CGM( new clang::CodeGen::CodeGenModule(C->getASTContext(), C->getCodeGenOpts(), *M, *TD, C->getDiagnostics())); llvm::OwningPtr CGT( new clang::CodeGen::CodeGenTypes(*CGM.get())); CodeGenInfo = (clang::TargetCodeGenInfo*) &CGM->getTargetCodeGenInfo(); CodeGenTypes = CGT.get(); auto parserTargetInfo = new ParserTargetInfo(); parserTargetInfo->ABI = AST->getTargetInfo().getABI(); parserTargetInfo->Char16Type = ConvertIntType(AST->getTargetInfo().getChar16Type()); parserTargetInfo->Char32Type = ConvertIntType(AST->getTargetInfo().getChar32Type()); parserTargetInfo->Int64Type = ConvertIntType(AST->getTargetInfo().getInt64Type()); parserTargetInfo->IntMaxType = ConvertIntType(AST->getTargetInfo().getIntMaxType()); parserTargetInfo->IntPtrType = ConvertIntType(AST->getTargetInfo().getIntPtrType()); parserTargetInfo->SizeType = ConvertIntType(AST->getTargetInfo().getSizeType()); parserTargetInfo->UIntMaxType = ConvertIntType(AST->getTargetInfo().getUIntMaxType()); parserTargetInfo->WCharType = ConvertIntType(AST->getTargetInfo().getWCharType()); parserTargetInfo->WIntType = ConvertIntType(AST->getTargetInfo().getWIntType()); parserTargetInfo->BoolAlign = AST->getTargetInfo().getBoolAlign(); parserTargetInfo->BoolWidth = AST->getTargetInfo().getBoolWidth(); parserTargetInfo->CharAlign = AST->getTargetInfo().getCharAlign(); parserTargetInfo->CharWidth = AST->getTargetInfo().getCharWidth(); parserTargetInfo->Char16Align = AST->getTargetInfo().getChar16Align(); parserTargetInfo->Char16Width = AST->getTargetInfo().getChar16Width(); parserTargetInfo->Char32Align = AST->getTargetInfo().getChar32Align(); parserTargetInfo->Char32Width = AST->getTargetInfo().getChar32Width(); parserTargetInfo->HalfAlign = AST->getTargetInfo().getHalfAlign(); parserTargetInfo->HalfWidth = AST->getTargetInfo().getHalfWidth(); parserTargetInfo->FloatAlign = AST->getTargetInfo().getFloatAlign(); parserTargetInfo->FloatWidth = AST->getTargetInfo().getFloatWidth(); parserTargetInfo->DoubleAlign = AST->getTargetInfo().getDoubleAlign(); parserTargetInfo->DoubleWidth = AST->getTargetInfo().getDoubleWidth(); parserTargetInfo->ShortAlign = AST->getTargetInfo().getShortAlign(); parserTargetInfo->ShortWidth = AST->getTargetInfo().getShortWidth(); parserTargetInfo->IntAlign = AST->getTargetInfo().getIntAlign(); parserTargetInfo->IntWidth = AST->getTargetInfo().getIntWidth(); parserTargetInfo->IntMaxTWidth = AST->getTargetInfo().getIntMaxTWidth(); parserTargetInfo->LongAlign = AST->getTargetInfo().getLongAlign(); parserTargetInfo->LongWidth = AST->getTargetInfo().getLongWidth(); parserTargetInfo->LongDoubleAlign = AST->getTargetInfo().getLongDoubleAlign(); parserTargetInfo->LongDoubleWidth = AST->getTargetInfo().getLongDoubleWidth(); parserTargetInfo->LongLongAlign = AST->getTargetInfo().getLongLongAlign(); parserTargetInfo->LongLongWidth = AST->getTargetInfo().getLongLongWidth(); parserTargetInfo->PointerAlign = AST->getTargetInfo().getPointerAlign(0); parserTargetInfo->PointerWidth = AST->getTargetInfo().getPointerWidth(0); parserTargetInfo->WCharAlign = AST->getTargetInfo().getWCharAlign(); parserTargetInfo->WCharWidth = AST->getTargetInfo().getWCharWidth(); return parserTargetInfo; }