Tools and libraries to glue C/C++ APIs to high-level languages
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

4962 lines
147 KiB

/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#ifdef DEBUG
#undef DEBUG // workaround DEBUG define messing with LLVM COFF headers
#endif
#include "Parser.h"
#include "ELFDumper.h"
#include "APValuePrinter.h"
#include <llvm/Support/Host.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Object/Archive.h>
#include <llvm/Object/COFF.h>
#include <llvm/Object/ObjectFile.h>
#include <llvm/Object/ELFObjectFile.h>
#include <llvm/Object/MachO.h>
#include <llvm/Option/ArgList.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/DataLayout.h>
#include <clang/Basic/Builtins.h>
#include <clang/Basic/Version.h>
#include <clang/Config/config.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/Comment.h>
#include <clang/AST/DeclFriend.h>
#include <clang/AST/ExprCXX.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Lex/DirectoryLookup.h>
#include <clang/Lex/HeaderSearch.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PreprocessorOptions.h>
#include <clang/Lex/PreprocessingRecord.h>
#include <clang/Parse/ParseAST.h>
#include <clang/Sema/Sema.h>
#include <clang/Sema/SemaConsumer.h>
#include <clang/Sema/Template.h>
#include <clang/Frontend/Utils.h>
#include <clang/Driver/Driver.h>
#include <clang/Driver/ToolChain.h>
#include <clang/Driver/Util.h>
#include <clang/Index/USRGeneration.h>
#include <CodeGen/TargetInfo.h>
#include <CodeGen/CGCall.h>
#include <CodeGen/CGCXXABI.h>
#include <Driver/ToolChains/Linux.h>
#include <Driver/ToolChains/MSVC.h>
#if defined(__APPLE__) || defined(__linux__)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#define HAVE_DLFCN
#endif
using namespace CppSharp::CppParser;
// We use this as a placeholder for pointer values that should be ignored.
void* IgnorePtr = reinterpret_cast<void*>(0x1);
//-----------------------------------//
Parser::Parser(CppParserOptions* Opts) : opts(Opts), index(0)
{
for (const auto& SupportedStdType : Opts->SupportedStdTypes)
supportedStdTypes.insert(SupportedStdType);
supportedStdTypes.insert("allocator");
supportedStdTypes.insert("basic_string");
supportedFunctionTemplates = { Opts->SupportedFunctionTemplates.begin(), Opts->SupportedFunctionTemplates.end() };
}
LayoutField Parser::WalkVTablePointer(Class* Class,
const clang::CharUnits& Offset, const std::string& prefix)
{
LayoutField LayoutField;
LayoutField.offset = Offset.getQuantity();
LayoutField.name = prefix + "_" + Class->name;
LayoutField.qualifiedType = GetQualifiedType(c->getASTContext().VoidPtrTy);
return LayoutField;
}
static CppAbi GetClassLayoutAbi(clang::TargetCXXABI::Kind abi)
{
switch (abi)
{
case clang::TargetCXXABI::Microsoft:
return CppAbi::Microsoft;
case clang::TargetCXXABI::GenericItanium:
return CppAbi::Itanium;
case clang::TargetCXXABI::GenericARM:
return CppAbi::ARM;
case clang::TargetCXXABI::iOS:
return CppAbi::iOS;
case clang::TargetCXXABI::AppleARM64:
return CppAbi::iOS64;
case clang::TargetCXXABI::WebAssembly:
return CppAbi::WebAssembly;
default:
llvm_unreachable("Unsupported C++ ABI kind");
}
}
void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD,
clang::CharUnits Offset, bool IncludeVirtualBases)
{
using namespace clang;
const auto &Layout = c->getASTContext().getASTRecordLayout(RD);
auto CXXRD = dyn_cast<CXXRecordDecl>(RD);
auto Parent = static_cast<AST::Class*>(
WalkDeclaration(RD));
if (Class != Parent)
{
LayoutBase LayoutBase;
LayoutBase.offset = Offset.getQuantity();
LayoutBase._class = Parent;
Class->layout->Bases.push_back(LayoutBase);
}
// Dump bases.
if (CXXRD) {
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
bool HasOwnVFPtr = Layout.hasOwnVFPtr();
bool HasOwnVBPtr = Layout.hasOwnVBPtr();
// Vtable pointer.
if (CXXRD->isDynamicClass() && !PrimaryBase &&
!c->getTarget().getCXXABI().isMicrosoft()) {
auto VPtr = WalkVTablePointer(Parent, Offset, "vptr");
Class->layout->Fields.push_back(VPtr);
}
else if (HasOwnVFPtr) {
auto VTPtr = WalkVTablePointer(Parent, Offset, "vfptr");
Class->layout->Fields.push_back(VTPtr);
}
// Collect nvbases.
SmallVector<const CXXRecordDecl *, 4> Bases;
for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
assert(!Base.getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
if (!Base.isVirtual())
Bases.push_back(Base.getType()->getAsCXXRecordDecl());
}
// Sort nvbases by offset.
std::stable_sort(Bases.begin(), Bases.end(),
[&](const CXXRecordDecl *L, const CXXRecordDecl *R) {
return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R);
});
// Dump (non-virtual) bases
for (const CXXRecordDecl *Base : Bases) {
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base);
ReadClassLayout(Class, Base, BaseOffset,
/*IncludeVirtualBases=*/false);
}
// vbptr (for Microsoft C++ ABI)
if (HasOwnVBPtr) {
auto VBPtr = WalkVTablePointer(Parent,
Offset + Layout.getVBPtrOffset(), "vbptr");
Class->layout->Fields.push_back(VBPtr);
}
}
// Dump fields.
uint64_t FieldNo = 0;
for (const clang::FieldDecl* Field : RD->fields()) {
uint64_t LocalFieldOffsetInBits = Layout.getFieldOffset(FieldNo++);
CharUnits FieldOffset =
Offset + c->getASTContext().toCharUnitsFromBits(LocalFieldOffsetInBits);
auto F = WalkFieldCXX(Field, Parent);
LayoutField LayoutField;
LayoutField.offset = FieldOffset.getQuantity();
LayoutField.name = F->name;
LayoutField.qualifiedType = GetQualifiedType(Field->getType());
LayoutField.fieldPtr = (void*)Field;
Class->layout->Fields.push_back(LayoutField);
}
// Dump virtual bases.
if (CXXRD && IncludeVirtualBases) {
const ASTRecordLayout::VBaseOffsetsMapTy &VtorDisps =
Layout.getVBaseOffsetsMap();
for (const CXXBaseSpecifier &Base : CXXRD->vbases()) {
assert(Base.isVirtual() && "Found non-virtual class!");
const CXXRecordDecl *VBase = Base.getType()->getAsCXXRecordDecl();
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase);
if (VtorDisps.find(VBase)->second.hasVtorDisp()) {
auto VtorDisp = WalkVTablePointer(Parent,
VBaseOffset - CharUnits::fromQuantity(4), "vtordisp");
Class->layout->Fields.push_back(VtorDisp);
}
ReadClassLayout(Class, VBase, VBaseOffset,
/*IncludeVirtualBases=*/false);
}
}
}
//-----------------------------------//
static clang::TargetCXXABI::Kind
ConvertToClangTargetCXXABI(CppSharp::CppParser::AST::CppAbi abi)
{
using namespace clang;
switch (abi)
{
case CppSharp::CppParser::AST::CppAbi::Itanium:
return TargetCXXABI::GenericItanium;
case CppSharp::CppParser::AST::CppAbi::Microsoft:
return TargetCXXABI::Microsoft;
case CppSharp::CppParser::AST::CppAbi::ARM:
return TargetCXXABI::GenericARM;
case CppSharp::CppParser::AST::CppAbi::iOS:
return TargetCXXABI::iOS;
case CppSharp::CppParser::AST::CppAbi::iOS64:
return TargetCXXABI::AppleARM64;
}
llvm_unreachable("Unsupported C++ ABI.");
}
void Parser::Setup(bool Compile)
{
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
using namespace clang;
std::vector<const char*> args;
args.push_back("-cc1");
if (Compile)
{
for (const std::string& CompilationOption : opts->CompilationOptions)
{
args.push_back(CompilationOption.c_str());
if (opts->verbose)
printf("Compiler argument: %s\n", CompilationOption.c_str());
}
}
for (unsigned I = 0, E = opts->Arguments.size(); I != E; ++I)
{
const auto& Arg = opts->Arguments[I];
args.push_back(Arg.c_str());
if (opts->verbose)
printf("Compiler argument: %s\n", Arg.c_str());
}
c.reset(new CompilerInstance());
c->createDiagnostics();
CompilerInvocation* Inv = new CompilerInvocation();
llvm::ArrayRef<const char*> arguments(args.data(), args.data() + args.size());
CompilerInvocation::CreateFromArgs(*Inv, arguments, c->getDiagnostics());
c->setInvocation(std::shared_ptr<CompilerInvocation>(Inv));
c->getLangOpts() = *Inv->LangOpts;
auto& TO = Inv->TargetOpts;
if (opts->targetTriple.empty())
opts->targetTriple = llvm::sys::getDefaultTargetTriple();
TO->Triple = llvm::Triple::normalize(opts->targetTriple);
if (opts->verbose)
printf("Target triple: %s\n", TO->Triple.c_str());
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.
opts->targetTriple = llvm::sys::getDefaultTargetTriple();
TO->Triple = llvm::Triple::normalize(opts->targetTriple);
TI = TargetInfo::CreateTargetInfo(c->getDiagnostics(), TO);
}
assert(TI && "Expected valid target info");
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 auto& s = opts->IncludeDirs[I];
HSOpts.AddPath(s, frontend::Angled, false, false);
}
for (unsigned I = 0, E = opts->SystemIncludeDirs.size(); I != E; ++I)
{
const auto& s = opts->SystemIncludeDirs[I];
HSOpts.AddPath(s, frontend::System, false, false);
}
for (unsigned I = 0, E = opts->Defines.size(); I != E; ++I)
{
const auto& define = opts->Defines[I];
PPOpts.addMacroDef(define);
}
for (unsigned I = 0, E = opts->Undefines.size(); I != E; ++I)
{
const auto& undefine = opts->Undefines[I];
PPOpts.addMacroUndef(undefine);
}
#ifdef _MSC_VER
if (opts->microsoftMode)
{
LangOpts.MSCompatibilityVersion = opts->toolSetToUse;
if (!LangOpts.MSCompatibilityVersion) LangOpts.MSCompatibilityVersion = 1700;
}
#endif
llvm::opt::InputArgList Args(0, 0);
clang::driver::Driver D("", TO->Triple, c->getDiagnostics());
clang::driver::ToolChain *TC = nullptr;
llvm::Triple Target(TO->Triple);
if (Target.getOS() == llvm::Triple::Linux)
TC = new clang::driver::toolchains::Linux(D, Target, Args);
else if (Target.getEnvironment() == llvm::Triple::EnvironmentType::MSVC)
TC = new clang::driver::toolchains::MSVCToolChain(D, Target, Args);
if (TC && !opts->noStandardIncludes) {
llvm::opt::ArgStringList Includes;
TC->AddClangSystemIncludeArgs(Args, Includes);
TC->AddClangCXXStdlibIncludeArgs(Args, Includes);
for (auto& Arg : Includes) {
if (strlen(Arg) > 0 && Arg[0] != '-')
HSOpts.AddPath(Arg, frontend::System, /*IsFramework=*/false,
/*IgnoreSysRoot=*/false);
}
}
if (TC)
delete TC;
// Enable preprocessing record.
PPOpts.DetailedRecord = true;
c->createPreprocessor(TU_Complete);
Preprocessor& PP = c->getPreprocessor();
PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
PP.getLangOpts());
c->createASTContext();
}
//-----------------------------------//
std::string Parser::GetDeclMangledName(const clang::Decl* D)
{
using namespace clang;
if(!D || !isa<NamedDecl>(D))
return "";
bool CanMangle = isa<FunctionDecl>(D) || isa<VarDecl>(D)
|| isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D);
if (!CanMangle) return "";
auto ND = cast<NamedDecl>(D);
std::unique_ptr<MangleContext> MC;
auto& AST = c->getASTContext();
auto targetABI = c->getTarget().getCXXABI().getKind();
switch(targetABI)
{
default:
MC.reset(ItaniumMangleContext::create(AST, AST.getDiagnostics()));
break;
case TargetCXXABI::Microsoft:
MC.reset(MicrosoftMangleContext::create(AST, AST.getDiagnostics()));
break;
}
if (!MC)
llvm_unreachable("Unknown mangling ABI");
std::string Mangled;
llvm::raw_string_ostream Out(Mangled);
bool IsDependent = false;
if (const ValueDecl *VD = dyn_cast<ValueDecl>(ND))
IsDependent |= VD->getType()->isDependentType();
if (!IsDependent)
IsDependent |= ND->getDeclContext()->isDependentContext();
if (!MC->shouldMangleDeclName(ND) || IsDependent)
return ND->getDeclName().getAsString();
GlobalDecl GD;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND))
GD = GlobalDecl(CD, Ctor_Base);
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND))
GD = GlobalDecl(DD, Dtor_Base);
else
GD = GlobalDecl(ND);
MC->mangleName(GD, 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().str();
return D->getNameAsString();
}
static std::string GetTagDeclName(const clang::TagDecl* D)
{
using namespace clang;
if (auto Typedef = D->getTypedefNameForAnonDecl())
{
assert(Typedef->getIdentifier() && "Typedef without identifier?");
return GetDeclName(Typedef);
}
return GetDeclName(D);
}
static std::string GetDeclUSR(const clang::Decl* D)
{
using namespace clang;
SmallString<128> usr;
if (!index::generateUSRForDecl(D, usr))
return usr.str().str();
return "<invalid>";
}
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 bool IsExplicit(const clang::Decl* D)
{
using namespace clang;
auto CTS = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D);
return !CTS ||
CTS->getSpecializationKind() == TSK_ExplicitSpecialization ||
CTS->getSpecializationKind() == TSK_ExplicitInstantiationDeclaration ||
CTS->getSpecializationKind() == TSK_ExplicitInstantiationDefinition;
}
static clang::SourceLocation GetDeclStartLocation(clang::CompilerInstance* C,
const clang::Decl* D)
{
auto& SM = C->getSourceManager();
auto startLoc = SM.getExpansionLoc(D->getBeginLoc());
auto startOffset = SM.getFileOffset(startLoc);
if (clang::dyn_cast_or_null<clang::TranslationUnitDecl>(D) || !startLoc.isValid())
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 || !IsExplicit(prevDecl))
return lineBeginLoc;
auto prevDeclEndLoc = SM.getExpansionLoc(prevDecl->getEndLoc());
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->getBeginLoc()) != 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<clang::TagType>();
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(const clang::QualType& Type)
{
TypeQualifiers quals;
quals.isConst = Type.isLocalConstQualified();
quals.isRestrict = Type.isLocalRestrictQualified();
quals.isVolatile = Type.isVolatileQualified();
return quals;
}
QualifiedType Parser::GetQualifiedType(clang::QualType qual, const clang::TypeLoc* TL)
{
if (qual.isNull())
return QualifiedType();
QualifiedType qualType;
qualType.type = WalkType(qual, TL);
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;
case clang::AS_none:
return AccessSpecifier::Public;
}
llvm_unreachable("Unknown AccessSpecifier");
}
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 = Component.getRTTIDecl();
VTC.declaration = WalkRecordCXX(RD);
break;
}
case clang::VTableComponent::CK_FunctionPointer:
{
VTC.kind = VTableComponentKind::FunctionPointer;
auto MD = Component.getFunctionDecl();
VTC.declaration = WalkMethodCXX(MD);
break;
}
case clang::VTableComponent::CK_CompleteDtorPointer:
{
VTC.kind = VTableComponentKind::CompleteDtorPointer;
auto MD = Component.getDestructorDecl();
VTC.declaration = WalkMethodCXX(MD);
break;
}
case clang::VTableComponent::CK_DeletingDtorPointer:
{
VTC.kind = VTableComponentKind::DeletingDtorPointer;
auto MD = Component.getDestructorDecl();
VTC.declaration = WalkMethodCXX(MD);
break;
}
case clang::VTableComponent::CK_UnusedFunctionPointer:
{
VTC.kind = VTableComponentKind::UnusedFunctionPointer;
auto MD = 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 (const auto& VTC : VTLayout.vtable_components())
{
auto VTComponent = WalkVTableComponent(VTC);
Layout.Components.push_back(VTComponent);
}
return Layout;
}
void Parser::WalkVTable(const clang::CXXRecordDecl* RD, Class* C)
{
using namespace clang;
assert(RD->isDynamicClass() && "Only dynamic classes have virtual tables");
if (!C->layout)
C->layout = new ClassLayout();
auto targetABI = c->getTarget().getCXXABI().getKind();
C->layout->ABI = GetClassLayoutAbi(targetABI);
auto& AST = c->getASTContext();
switch(targetABI)
{
case TargetCXXABI::Microsoft:
{
MicrosoftVTableContext VTContext(AST);
const auto& VFPtrs = VTContext.getVFPtrOffsets(RD);
for (const auto& VFPtrInfo : VFPtrs)
{
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:
{
ItaniumVTableContext VTContext(AST);
auto& VTLayout = VTContext.getVTableLayout(RD);
C->layout->layout = WalkVTableLayout(VTLayout);
break;
}
default:
llvm_unreachable("Unsupported C++ ABI kind");
}
}
void Parser::EnsureCompleteRecord(const clang::RecordDecl* Record,
DeclarationContext* NS, Class* RC)
{
using namespace clang;
if (!RC->isIncomplete || RC->completeDeclaration)
return;
Decl* Definition;
if (auto CXXRecord = dyn_cast<CXXRecordDecl>(Record))
Definition = CXXRecord->getDefinition();
else
Definition = Record->getDefinition();
if (!Definition)
return;
RC->completeDeclaration = WalkDeclaration(Definition);
}
Class* Parser::GetRecord(const clang::RecordDecl* Record, bool& Process)
{
using namespace clang;
Process = false;
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)
{
auto USR = GetDeclUSR(Record);
if (auto AR = NS->FindAnonymous(USR))
RC = static_cast<Class*>(AR);
}
else
{
RC = NS->FindClass(opts->unityBuild ? Record : 0, Name,
isCompleteDefinition, /*Create=*/false);
}
if (RC)
return RC;
RC = NS->FindClass(opts->unityBuild ? Record : 0, Name,
isCompleteDefinition, /*Create=*/true);
RC->isInjected = Record->isInjectedClassName();
HandleDeclaration(Record, RC);
EnsureCompleteRecord(Record, NS, RC);
for (auto Redecl : Record->redecls())
{
if (Redecl->isImplicit() || Redecl == Record)
continue;
RC->Redeclarations.push_back(WalkDeclaration(Redecl));
}
if (HasEmptyName)
{
auto USR = GetDeclUSR(Record);
NS->anonymous[USR] = RC;
}
if (!isCompleteDefinition)
return RC;
Process = true;
return RC;
}
Class* Parser::WalkRecord(const clang::RecordDecl* Record)
{
bool Process;
auto RC = GetRecord(Record, Process);
if (!RC || !Process)
return RC;
WalkRecord(Record, RC);
return RC;
}
Class* Parser::WalkRecordCXX(const clang::CXXRecordDecl* Record)
{
bool Process;
auto RC = GetRecord(Record, Process);
if (!RC || !Process)
return RC;
WalkRecordCXX(Record, RC);
return RC;
}
static int I = 0;
static bool IsRecordValid(const clang::RecordDecl* RC,
std::unordered_set<const clang::RecordDecl*>& Visited)
{
using namespace clang;
if (Visited.find(RC) != Visited.end())
return true;
Visited.insert(RC);
if (RC->isInvalidDecl())
return false;
for (auto Field : RC->fields())
{
auto Type = Field->getType()->getUnqualifiedDesugaredType();
const auto* RD = const_cast<CXXRecordDecl*>(Type->getAsCXXRecordDecl());
if (!RD)
RD = Type->getPointeeCXXRecordDecl();
if (RD && !IsRecordValid(RD, Visited))
return false;
}
return true;
}
static bool IsRecordValid(const clang::RecordDecl* RC)
{
std::unordered_set<const clang::RecordDecl*> Visited;
return IsRecordValid(RC, Visited);
}
static clang::CXXRecordDecl* GetCXXRecordDeclFromTemplateName(const clang::TemplateName& Name)
{
using namespace clang;
switch (Name.getKind()) {
case clang::TemplateName::Template:
return dyn_cast<clang::CXXRecordDecl>(
Name.getAsTemplateDecl()->getTemplatedDecl());
case clang::TemplateName::QualifiedTemplate:
return dyn_cast<clang::CXXRecordDecl>(
Name.getAsQualifiedTemplateName()->getTemplateDecl()->getTemplatedDecl());
default:
assert(0 && "Unknown template name kind");
return nullptr;
}
}
static clang::CXXRecordDecl* GetCXXRecordDeclFromBaseType(const clang::QualType& Ty)
{
using namespace clang;
if (auto RT = Ty->getAs<clang::RecordType>())
return dyn_cast<clang::CXXRecordDecl>(RT->getDecl());
else if (auto TST = Ty->getAs<clang::TemplateSpecializationType>())
return GetCXXRecordDeclFromTemplateName(TST->getTemplateName());
else if (auto Injected = Ty->getAs<clang::InjectedClassNameType>())
return Injected->getDecl();
assert("Could not get base CXX record from type");
return nullptr;
}
bool Parser::HasLayout(const clang::RecordDecl* Record)
{
if (opts->skipLayoutInfo)
return false;
if (Record->isDependentType() || !Record->getDefinition() ||
!IsRecordValid(Record))
return false;
if (auto CXXRecord = llvm::dyn_cast<clang::CXXRecordDecl>(Record))
for (const clang::CXXBaseSpecifier& Base : CXXRecord->bases())
{
auto CXXBase = GetCXXRecordDeclFromBaseType(Base.getType());
if (!CXXBase || !HasLayout(CXXBase))
return false;
}
return true;
}
bool Parser::IsSupported(const clang::NamedDecl* ND)
{
return !c->getSourceManager().isInSystemHeader(ND->getBeginLoc()) ||
(llvm::isa<clang::RecordDecl>(ND) &&
supportedStdTypes.find(ND->getName().str()) != supportedStdTypes.end());
}
bool Parser::IsSupported(const clang::CXXMethodDecl* MD)
{
using namespace clang;
return !c->getSourceManager().isInSystemHeader(MD->getBeginLoc()) ||
(isa<CXXConstructorDecl>(MD) && MD->getNumParams() == 0) ||
isa<CXXDestructorDecl>(MD) ||
(MD->getDeclName().isIdentifier() &&
((MD->getName() == "data" && MD->getNumParams() == 0 && MD->isConst()) ||
(MD->getName() == "assign" && MD->getNumParams() == 1 &&
MD->parameters()[0]->getType()->isPointerType())) &&
supportedStdTypes.find(MD->getParent()->getName().str()) !=
supportedStdTypes.end());
}
static RecordArgABI GetRecordArgABI(
clang::CodeGen::CGCXXABI::RecordArgABI argAbi)
{
using namespace clang::CodeGen;
switch (argAbi)
{
case CGCXXABI::RecordArgABI::RAA_DirectInMemory:
return RecordArgABI::DirectInMemory;
case CGCXXABI::RecordArgABI::RAA_Indirect:
return RecordArgABI::Indirect;
default:
return RecordArgABI::Default;
}
}
static TagKind ConvertToTagKind(clang::TagTypeKind AS)
{
switch (AS)
{
case clang::TagTypeKind::TTK_Struct:
return TagKind::Struct;
case clang::TagTypeKind::TTK_Interface:
return TagKind::Interface;
case clang::TagTypeKind::TTK_Union:
return TagKind::Union;
case clang::TagTypeKind::TTK_Class:
return TagKind::Class;
case clang::TagTypeKind::TTK_Enum:
return TagKind::Enum;
}
llvm_unreachable("Unknown TagKind");
}
void Parser::WalkRecord(const clang::RecordDecl* Record, Class* RC)
{
using namespace clang;
if (Record->isImplicit())
return;
if (IsExplicit(Record))
{
auto headStartLoc = GetDeclStartLocation(c.get(), Record);
auto headEndLoc = Record->getLocation(); // identifier location
auto bodyEndLoc = Record->getEndLoc();
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();
RC->isUnion = Record->isUnion();
RC->isDependent = Record->isDependentType();
RC->isExternCContext = Record->isExternCContext();
RC->tagKind = ConvertToTagKind(Record->getTagKind());
bool hasLayout = HasLayout(Record);
if (hasLayout)
{
if (!RC->layout)
RC->layout = new ClassLayout();
auto targetABI = c->getTarget().getCXXABI().getKind();
RC->layout->ABI = GetClassLayoutAbi(targetABI);
if (auto CXXRD = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(Record))
{
auto& CXXABI = codeGenTypes->getCXXABI();
RC->layout->argABI = GetRecordArgABI(CXXABI.getRecordArgABI(CXXRD));
}
const auto& 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();
ReadClassLayout(RC, Record, CharUnits(), true);
}
for (auto FD : Record->fields())
WalkFieldCXX(FD, RC);
if (c->getSourceManager().isInSystemHeader(Record->getBeginLoc()))
{
if (supportedStdTypes.find(Record->getName().str()) != supportedStdTypes.end())
{
for (auto D : Record->decls())
{
switch (D->getKind())
{
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion:
case Decl::CXXMethod:
{
auto MD = cast<CXXMethodDecl>(D);
if (IsSupported(MD))
WalkDeclaration(MD);
break;
}
default:
break;
}
}
}
return;
}
if (opts->skipPrivateDeclarations &&
Record->getAccess() == clang::AccessSpecifier::AS_private)
return;
for (auto D : Record->decls())
{
switch (D->getKind())
{
case Decl::AccessSpec:
{
AccessSpecDecl* AS = cast<AccessSpecDecl>(D);
auto AccessDecl = new AccessSpecifierDecl();
HandleDeclaration(AS, AccessDecl);
AccessDecl->access = ConvertToAccess(AS->getAccess());
AccessDecl->_namespace = RC;
RC->Specifiers.push_back(AccessDecl);
break;
}
case Decl::Field: // fields already handled
case Decl::IndirectField: // FIXME: Handle indirect fields
break;
case Decl::CXXRecord:
// Handle implicit records inside the class.
if (D->isImplicit())
continue;
WalkDeclaration(D);
break;
case Decl::Friend:
{
FriendDecl* FD = cast<FriendDecl>(D);
auto decl = FD->getFriendDecl();
// Skip every friend declaration that isn't a function declaration
if (decl && !isa<FunctionDecl>(decl))
continue;
WalkDeclaration(D);
break;
}
case Decl::FriendTemplate:
{
// In this case always skip the declaration since, unlike Decl::Friend handled above,
// it never is a declaration of a friend function or method
break;
}
default:
{
WalkDeclaration(D);
break;
} }
}
}
void Parser::WalkRecordCXX(const clang::CXXRecordDecl* Record, Class* RC)
{
using namespace clang;
if (Record->isImplicit())
return;
auto& Sema = c->getSema();
Sema.ForceDeclarationOfImplicitMembers(const_cast<clang::CXXRecordDecl*>(Record));
WalkRecord(Record, RC);
if (!Record->hasDefinition())
return;
RC->isPOD = Record->isPOD();
RC->isAbstract = Record->isAbstract();
RC->isDynamic = Record->isDynamicClass();
RC->isPolymorphic = Record->isPolymorphic();
RC->hasNonTrivialDefaultConstructor = Record->hasNonTrivialDefaultConstructor();
RC->hasNonTrivialCopyConstructor = Record->hasNonTrivialCopyConstructor();
RC->hasNonTrivialDestructor = Record->hasNonTrivialDestructor();
bool hasLayout = HasLayout(Record) &&
Record->getDeclName() != c->getSema().VAListTagName;
// Get the record layout information.
const ASTRecordLayout* Layout = 0;
if (hasLayout)
{
Layout = &c->getASTContext().getASTRecordLayout(Record);
assert (RC->layout && "Expected a valid AST layout");
RC->layout->hasOwnVFPtr = Layout->hasOwnVFPtr();
RC->layout->VBPtrOffset = Layout->getVBPtrOffset().getQuantity();
}
// Iterate through the record bases.
for (const CXXBaseSpecifier& BS : Record->bases())
{
BaseClassSpecifier* Base = new BaseClassSpecifier();
Base->access = ConvertToAccess(BS.getAccessSpecifier());
Base->isVirtual = BS.isVirtual();
auto BSTL = BS.getTypeSourceInfo()->getTypeLoc();
Base->type = WalkType(BS.getType(), &BSTL);
auto BaseDecl = GetCXXRecordDeclFromBaseType(BS.getType());
if (BaseDecl && Layout)
{
auto Offset = BS.isVirtual() ? Layout->getVBaseClassOffset(BaseDecl)
: Layout->getBaseClassOffset(BaseDecl);
Base->offset = Offset.getQuantity();
}
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");
}
//-----------------------------------//
struct Diagnostic
{
clang::SourceLocation Location;
llvm::SmallString<100> Message;
clang::DiagnosticsEngine::Level Level = clang::DiagnosticsEngine::Level::Ignored;
};
struct DiagnosticConsumer : public clang::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++;
if (Decl)
{
Decl->setInvalidDecl();
Decl = 0;
}
}
auto Diag = Diagnostic();
Diag.Location = Info.getLocation();
Diag.Level = Level;
Info.FormatDiagnostic(Diag.Message);
Diagnostics.push_back(Diag);
}
std::vector<Diagnostic> Diagnostics;
clang::Decl* Decl = 0;
};
ClassTemplateSpecialization*
Parser::WalkClassTemplateSpecialization(const clang::ClassTemplateSpecializationDecl* CTS)
{
using namespace clang;
auto CT = WalkClassTemplate(CTS->getSpecializedTemplate());
auto USR = GetDeclUSR(CTS);
auto TS = CT->FindSpecialization(USR);
if (TS != nullptr)
return TS;
TS = new ClassTemplateSpecialization();
HandleDeclaration(CTS, TS);
auto NS = GetNamespace(CTS);
assert(NS && "Expected a valid namespace");
TS->_namespace = NS;
TS->name = CTS->getName().str();
TS->templatedDecl = CT;
TS->specializationKind = WalkTemplateSpecializationKind(CTS->getSpecializationKind());
CT->Specializations.push_back(TS);
auto& TAL = CTS->getTemplateArgs();
auto TSI = CTS->getTypeAsWritten();
if (TSI)
{
auto TL = TSI->getTypeLoc();
auto TSL = TL.getAs<TemplateSpecializationTypeLoc>();
TS->Arguments = WalkTemplateArgumentList(&TAL, &TSL);
}
else
{
TS->Arguments = WalkTemplateArgumentList(&TAL, (clang::TemplateSpecializationTypeLoc*) 0);
}
if (CTS->isCompleteDefinition())
{
WalkRecordCXX(CTS, TS);
}
else
{
TS->isIncomplete = true;
if (CTS->getDefinition())
{
auto Complete = WalkDeclarationDef(CTS->getDefinition());
if (!Complete->isIncomplete)
TS->completeDeclaration = Complete;
}
}
return TS;
}
//-----------------------------------//
ClassTemplatePartialSpecialization*
Parser::WalkClassTemplatePartialSpecialization(const clang::ClassTemplatePartialSpecializationDecl* CTS)
{
using namespace clang;
auto CT = WalkClassTemplate(CTS->getSpecializedTemplate());
auto USR = GetDeclUSR(CTS);
auto TS = CT->FindPartialSpecialization(USR);
if (TS != nullptr)
return TS;
TS = new ClassTemplatePartialSpecialization();
HandleDeclaration(CTS, TS);
auto NS = GetNamespace(CTS);
assert(NS && "Expected a valid namespace");
TS->_namespace = NS;
TS->name = CTS->getName().str();
TS->templatedDecl = CT;
TS->specializationKind = WalkTemplateSpecializationKind(CTS->getSpecializationKind());
CT->Specializations.push_back(TS);
auto& TAL = CTS->getTemplateArgs();
if (auto TSI = CTS->getTypeAsWritten())
{
auto TL = TSI->getTypeLoc();
auto TSL = TL.getAs<TemplateSpecializationTypeLoc>();
TS->Arguments = WalkTemplateArgumentList(&TAL, &TSL);
}
if (CTS->isCompleteDefinition())
{
WalkRecordCXX(CTS, TS);
}
else
{
TS->isIncomplete = true;
if (CTS->getDefinition())
{
auto Complete = WalkDeclarationDef(CTS->getDefinition());
if (!Complete->isIncomplete)
TS->completeDeclaration = Complete;
}
}
return TS;
}
//-----------------------------------//
std::vector<Declaration*> Parser::WalkTemplateParameterList(const clang::TemplateParameterList* TPL)
{
auto params = std::vector<CppSharp::CppParser::Declaration*>();
for (auto it = TPL->begin(); it != TPL->end(); ++it)
{
auto ND = *it;
auto TP = WalkDeclaration(ND);
params.push_back(TP);
}
return params;
}
//-----------------------------------//
ClassTemplate* Parser::WalkClassTemplate(const clang::ClassTemplateDecl* TD)
{
auto NS = GetNamespace(TD);
assert(NS && "Expected a valid namespace");
auto USR = GetDeclUSR(TD);
auto CT = NS->FindTemplate<ClassTemplate>(USR);
if (CT != nullptr)
return CT;
CT = new ClassTemplate();
HandleDeclaration(TD, CT);
CT->name = GetDeclName(TD);
CT->_namespace = NS;
NS->Templates.push_back(CT);
bool Process;
auto RC = GetRecord(TD->getTemplatedDecl(), Process);
CT->TemplatedDecl = RC;
if (Process)
WalkRecordCXX(TD->getTemplatedDecl(), RC);
CT->Parameters = WalkTemplateParameterList(TD->getTemplateParameters());
return CT;
}
//-----------------------------------//
TemplateTemplateParameter* Parser::WalkTemplateTemplateParameter(const clang::TemplateTemplateParmDecl* TTP)
{
auto TP = walkedTemplateTemplateParameters[TTP];
if (TP)
return TP;
TP = new TemplateTemplateParameter();
HandleDeclaration(TTP, TP);
TP->Parameters = WalkTemplateParameterList(TTP->getTemplateParameters());
TP->isParameterPack = TTP->isParameterPack();
TP->isPackExpansion = TTP->isPackExpansion();
TP->isExpandedParameterPack = TTP->isExpandedParameterPack();
if (TTP->getTemplatedDecl())
{
auto TD = WalkDeclaration(TTP->getTemplatedDecl());
TP->TemplatedDecl = TD;
}
walkedTemplateTemplateParameters[TTP] = TP;
return TP;
}
//-----------------------------------//
TypeTemplateParameter* Parser::WalkTypeTemplateParameter(const clang::TemplateTypeParmDecl* TTPD)
{
auto TP = walkedTypeTemplateParameters[TTPD];
if (TP)
return TP;
TP = new CppSharp::CppParser::TypeTemplateParameter();
TP->name = GetDeclName(TTPD);
HandleDeclaration(TTPD, TP);
if (TTPD->hasDefaultArgument())
TP->defaultArgument = GetQualifiedType(TTPD->getDefaultArgument());
TP->depth = TTPD->getDepth();
TP->index = TTPD->getIndex();
TP->isParameterPack = TTPD->isParameterPack();
walkedTypeTemplateParameters[TTPD] = TP;
return TP;
}
//-----------------------------------//
NonTypeTemplateParameter* Parser::WalkNonTypeTemplateParameter(const clang::NonTypeTemplateParmDecl* NTTPD)
{
auto NTP = walkedNonTypeTemplateParameters[NTTPD];
if (NTP)
return NTP;
NTP = new CppSharp::CppParser::NonTypeTemplateParameter();
NTP->name = GetDeclName(NTTPD);
HandleDeclaration(NTTPD, NTP);
if (NTTPD->hasDefaultArgument())
NTP->defaultArgument = WalkExpressionObsolete(NTTPD->getDefaultArgument());
NTP->type = GetQualifiedType(NTTPD->getType());
NTP->depth = NTTPD->getDepth();
NTP->index = NTTPD->getIndex();
NTP->isParameterPack = NTTPD->isParameterPack();
walkedNonTypeTemplateParameters[NTTPD] = NTP;
return NTP;
}
//-----------------------------------//
UnresolvedUsingTypename* Parser::WalkUnresolvedUsingTypename(const clang::UnresolvedUsingTypenameDecl* UUTD)
{
auto UUT = new CppSharp::CppParser::UnresolvedUsingTypename();
HandleDeclaration(UUTD, UUT);
return UUT;
}
//-----------------------------------//
template<typename TypeLoc>
std::vector<CppSharp::CppParser::TemplateArgument>
Parser::WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL,
TypeLoc* TSTL)
{
using namespace clang;
auto LocValid = TSTL && !TSTL->isNull() && TSTL->getTypePtr();
auto params = std::vector<CppSharp::CppParser::TemplateArgument>();
auto typeLocNumArgs = LocValid ? TSTL->getNumArgs() : 0;
for (size_t i = 0, e = TAL->size(); i < e; i++)
{
const clang::TemplateArgument& TA = TAL->get(i);
TemplateArgumentLoc TArgLoc;
TemplateArgumentLoc *ArgLoc = 0;
if (i < typeLocNumArgs && e == typeLocNumArgs)
{
TArgLoc = TSTL->getArgLoc(i);
ArgLoc = &TArgLoc;
}
auto Arg = WalkTemplateArgument(TA, ArgLoc);
params.push_back(Arg);
}
return params;
}
//-----------------------------------//
std::vector<CppSharp::CppParser::TemplateArgument>
Parser::WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL,
const clang::ASTTemplateArgumentListInfo* TALI)
{
using namespace clang;
auto params = std::vector<CppSharp::CppParser::TemplateArgument>();
for (size_t i = 0, e = TAL->size(); i < e; i++)
{
const clang::TemplateArgument& TA = TAL->get(i);
if (TALI)
{
auto ArgLoc = TALI->operator[](i);
auto TP = WalkTemplateArgument(TA, &ArgLoc);
params.push_back(TP);
}
else
{
auto TP = WalkTemplateArgument(TA, 0);
params.push_back(TP);
}
}
return params;
}
//-----------------------------------//
CppSharp::CppParser::TemplateArgument
Parser::WalkTemplateArgument(const clang::TemplateArgument& TA,
clang::TemplateArgumentLoc* ArgLoc)
{
auto Arg = CppSharp::CppParser::TemplateArgument();
switch (TA.getKind())
{
case clang::TemplateArgument::Type:
{
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::Type;
clang::TypeLoc ArgTL;
if (ArgLoc && ArgLoc->getTypeSourceInfo())
{
ArgTL = ArgLoc->getTypeSourceInfo()->getTypeLoc();
}
auto Type = TA.getAsType();
CompleteIfSpecializationType(Type);
Arg.type = GetQualifiedType(Type, &ArgTL);
break;
}
case clang::TemplateArgument::Declaration:
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::Declaration;
Arg.declaration = WalkDeclaration(TA.getAsDecl());
break;
case clang::TemplateArgument::NullPtr:
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::NullPtr;
break;
case clang::TemplateArgument::Integral:
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::Integral;
//Arg.Type = WalkType(TA.getIntegralType(), 0);
{
clang::TypeLoc ArgTL;
if (ArgLoc && ArgLoc->getTypeSourceInfo())
ArgTL = ArgLoc->getTypeSourceInfo()->getTypeLoc();
Arg.type = GetQualifiedType(TA.getIntegralType(), &ArgTL);
}
Arg.integral = TA.getAsIntegral().getLimitedValue();
break;
case clang::TemplateArgument::Template:
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::Template;
break;
case clang::TemplateArgument::TemplateExpansion:
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::TemplateExpansion;
break;
case clang::TemplateArgument::Expression:
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::Expression;
break;
case clang::TemplateArgument::Pack:
Arg.kind = CppSharp::CppParser::TemplateArgument::ArgumentKind::Pack;
break;
case clang::TemplateArgument::Null:
default:
llvm_unreachable("Unknown TemplateArgument");
}
return Arg;
}
//-----------------------------------//
TypeAliasTemplate* Parser::WalkTypeAliasTemplate(
const clang::TypeAliasTemplateDecl* TD)
{
using namespace clang;
auto NS = GetNamespace(TD);
assert(NS && "Expected a valid namespace");
auto USR = GetDeclUSR(TD);
auto TA = NS->FindTemplate<TypeAliasTemplate>(USR);
if (TA != nullptr)
return TA;
TA = new TypeAliasTemplate();
HandleDeclaration(TD, TA);
TA->name = GetDeclName(TD);
NS->Templates.push_back(TA);
TA->TemplatedDecl = WalkDeclaration(TD->getTemplatedDecl());
TA->Parameters = WalkTemplateParameterList(TD->getTemplateParameters());
return TA;
}
//-----------------------------------//
FunctionTemplate* Parser::WalkFunctionTemplate(const clang::FunctionTemplateDecl* TD)
{
if (opts->skipPrivateDeclarations &&
TD->getAccess() == clang::AccessSpecifier::AS_private)
return nullptr;
using namespace clang;
auto NS = GetNamespace(TD);
assert(NS && "Expected a valid namespace");
auto USR = GetDeclUSR(TD);
auto FT = NS->FindTemplate<FunctionTemplate>(USR);
if (FT != nullptr)
return FT;
CppSharp::CppParser::AST::Function* F = nullptr;
auto TemplatedDecl = TD->getTemplatedDecl();
if (auto MD = dyn_cast<CXXMethodDecl>(TemplatedDecl))
F = WalkMethodCXX(MD);
else
F = WalkFunction(TemplatedDecl);
FT = new FunctionTemplate();
HandleDeclaration(TD, FT);
FT->name = GetDeclName(TD);
FT->_namespace = NS;
FT->TemplatedDecl = F;
FT->Parameters = WalkTemplateParameterList(TD->getTemplateParameters());
NS->Templates.push_back(FT);
std::string qualifiedName;
llvm::raw_string_ostream as(qualifiedName);
TD->printQualifiedName(as);
if (supportedFunctionTemplates.find(as.str()) == supportedFunctionTemplates.end())
return FT;
for (auto&& FD : TD->specializations())
{
if (auto MD = dyn_cast<CXXMethodDecl>(FD))
WalkMethodCXX(MD);
else
WalkFunction(FD);
}
return FT;
}
//-----------------------------------//
CppSharp::CppParser::FunctionTemplateSpecialization*
Parser::WalkFunctionTemplateSpec(clang::FunctionTemplateSpecializationInfo* FTSI, CppSharp::CppParser::Function* Function)
{
using namespace clang;
auto FT = WalkFunctionTemplate(FTSI->getTemplate());
auto USR = GetDeclUSR(FTSI->getFunction());
auto FTS = FT->FindSpecialization(USR);
if (FTS != nullptr)
return FTS;
FTS = new CppSharp::CppParser::FunctionTemplateSpecialization();
FTS->specializationKind = WalkTemplateSpecializationKind(FTSI->getTemplateSpecializationKind());
FTS->specializedFunction = Function;
FTS->_template = WalkFunctionTemplate(FTSI->getTemplate());
FTS->_template->Specializations.push_back(FTS);
if (auto TSA = FTSI->TemplateArguments)
{
if (auto TSAW = FTSI->TemplateArgumentsAsWritten)
{
if (TSA->size() == TSAW->NumTemplateArgs)
{
FTS->Arguments = WalkTemplateArgumentList(TSA, TSAW);
return FTS;
}
}
FTS->Arguments = WalkTemplateArgumentList(TSA,
(const clang::ASTTemplateArgumentListInfo*) 0);
}
return FTS;
}
//-----------------------------------//
VarTemplate* Parser::WalkVarTemplate(const clang::VarTemplateDecl* TD)
{
auto NS = GetNamespace(TD);
assert(NS && "Expected a valid namespace");
auto USR = GetDeclUSR(TD);
auto VT = NS->FindTemplate<VarTemplate>(USR);
if (VT != nullptr)
return VT;
VT = new VarTemplate();
HandleDeclaration(TD, VT);
VT->name = GetDeclName(TD);
VT->_namespace = NS;
NS->Templates.push_back(VT);
auto RC = WalkVariable(TD->getTemplatedDecl());
VT->TemplatedDecl = RC;
VT->Parameters = WalkTemplateParameterList(TD->getTemplateParameters());
return VT;
}
VarTemplateSpecialization*
Parser::WalkVarTemplateSpecialization(const clang::VarTemplateSpecializationDecl* VTS)
{
using namespace clang;
auto VT = WalkVarTemplate(VTS->getSpecializedTemplate());
auto USR = GetDeclUSR(VTS);
auto TS = VT->FindSpecialization(USR);
if (TS != nullptr)
return TS;
TS = new VarTemplateSpecialization();
HandleDeclaration(VTS, TS);
auto NS = GetNamespace(VTS);
assert(NS && "Expected a valid namespace");
TS->_namespace = NS;
TS->name = VTS->getName().str();
TS->templatedDecl = VT;
TS->specializationKind = WalkTemplateSpecializationKind(VTS->getSpecializationKind());
VT->Specializations.push_back(TS);
auto& TAL = VTS->getTemplateArgs();
auto TSI = VTS->getTypeAsWritten();
if (TSI)
{
auto TL = TSI->getTypeLoc();
auto TSL = TL.getAs<TemplateSpecializationTypeLoc>();
TS->Arguments = WalkTemplateArgumentList(&TAL, &TSL);
}
else
{
TS->Arguments = WalkTemplateArgumentList(&TAL, (clang::TemplateSpecializationTypeLoc*) 0);
}
WalkVariable(VTS, TS);
return TS;
}
VarTemplatePartialSpecialization*
Parser::WalkVarTemplatePartialSpecialization(const clang::VarTemplatePartialSpecializationDecl* VTS)
{
using namespace clang;
auto VT = WalkVarTemplate(VTS->getSpecializedTemplate());
auto USR = GetDeclUSR(VTS);
auto TS = VT->FindPartialSpecialization(USR);
if (TS != nullptr)
return TS;
TS = new VarTemplatePartialSpecialization();
HandleDeclaration(VTS, TS);
auto NS = GetNamespace(VTS);
assert(NS && "Expected a valid namespace");
TS->_namespace = NS;
TS->name = VTS->getName().str();
TS->templatedDecl = VT;
TS->specializationKind = WalkTemplateSpecializationKind(VTS->getSpecializationKind());
VT->Specializations.push_back(TS);
auto& TAL = VTS->getTemplateArgs();
if (auto TSI = VTS->getTypeAsWritten())
{
auto TL = TSI->getTypeLoc();
auto TSL = TL.getAs<TemplateSpecializationTypeLoc>();
TS->Arguments = WalkTemplateArgumentList(&TAL, &TSL);
}
WalkVariable(VTS, TS);
return TS;
}
//-----------------------------------//
static CXXMethodKind GetMethodKindFromDecl(clang::DeclarationName Name)
{
using namespace clang;
switch(Name.getNameKind())
{
case DeclarationName::Identifier:
case DeclarationName::CXXDeductionGuideName:
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())
{
case OO_None:
return CXXOperatorKind::None;
case NUM_OVERLOADED_OPERATORS:
break;
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case OO_##Name: return CXXOperatorKind::Name;
#include "clang/Basic/OperatorKinds.def"
}
llvm_unreachable("Unknown OverloadedOperator");
}
Method* Parser::WalkMethodCXX(const clang::CXXMethodDecl* MD)
{
const clang::CXXConstructorDecl* Ctor;
if (opts->skipPrivateDeclarations &&
MD->getAccess() == clang::AccessSpecifier::AS_private &&
!MD->isVirtual() &&
!MD->isCopyAssignmentOperator() &&
!MD->isMoveAssignmentOperator() &&
(!(Ctor = llvm::dyn_cast<clang::CXXConstructorDecl>(MD)) ||
(!Ctor->isDefaultConstructor() && !Ctor->isCopyOrMoveConstructor())))
return nullptr;
using namespace clang;
// We could be in a redeclaration, so process the primary context.
if (MD->getPrimaryContext() != MD)
return WalkMethodCXX(cast<CXXMethodDecl>(MD->getPrimaryContext()));
auto RD = MD->getParent();
auto Decl = WalkDeclaration(RD);
auto Class = static_cast<CppSharp::CppParser::AST::Class*>(Decl);
// Check for an already existing method that came from the same declaration.
auto USR = GetDeclUSR(MD);
for (auto& M : Class->Methods)
{
if (M->USR == USR)
{
return M;
}
}
for (unsigned I = 0, E = Class->Templates.size(); I != E; ++I)
{
Template* Template = Class->Templates[I];
if (Template->TemplatedDecl->USR == USR)
return static_cast<Method*>(Template->TemplatedDecl);
}
auto Method = new CppSharp::CppParser::Method();
HandleDeclaration(MD, Method);
Method->access = ConvertToAccess(MD->getAccess());
Method->methodKind = GetMethodKindFromDecl(MD->getDeclName());
Method->isStatic = MD->isStatic();
Method->isVirtual = MD->isVirtual();
Method->isConst = MD->isConst();
for (auto OverriddenMethod : MD->overridden_methods())
{
auto OM = WalkMethodCXX(OverriddenMethod);
Method->OverriddenMethods.push_back(OM);
}
switch (MD->getRefQualifier())
{
case clang::RefQualifierKind::RQ_None:
Method->refQualifier = RefQualifierKind::None;
break;
case clang::RefQualifierKind::RQ_LValue:
Method->refQualifier = RefQualifierKind::LValue;
break;
case clang::RefQualifierKind::RQ_RValue:
Method->refQualifier = RefQualifierKind::RValue;
break;
}
Class->Methods.push_back(Method);
WalkFunction(MD, Method);
if (const CXXConstructorDecl* CD = dyn_cast<CXXConstructorDecl>(MD))
{
Method->isDefaultConstructor = CD->isDefaultConstructor();
Method->isCopyConstructor = CD->isCopyConstructor();
Method->isMoveConstructor = CD->isMoveConstructor();
Method->isExplicit = CD->isExplicit();
}
else if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
{
}
else if (const CXXConversionDecl* CD = dyn_cast<CXXConversionDecl>(MD))
{
auto TL = MD->getTypeSourceInfo()->getTypeLoc().castAs<FunctionTypeLoc>();
auto RTL = TL.getReturnLoc();
Method->conversionType = GetQualifiedType(CD->getConversionType(), &RTL);
}
return Method;
}
//-----------------------------------//
Field* Parser::WalkFieldCXX(const clang::FieldDecl* FD, Class* Class)
{
using namespace clang;
const auto& USR = GetDeclUSR(FD);
auto FoundField = std::find_if(Class->Fields.begin(), Class->Fields.end(),
[&](Field* Field) { return Field->USR == USR; });
if (FoundField != Class->Fields.end())
return *FoundField;
auto F = new Field();
HandleDeclaration(FD, F);
F->_namespace = Class;
F->name = FD->getName().str();
auto TL = FD->getTypeSourceInfo()->getTypeLoc();
F->qualifiedType = GetQualifiedType(FD->getType(), &TL);
F->access = ConvertToAccess(FD->getAccess());
F->_class = Class;
F->isBitField = FD->isBitField();
if (F->isBitField && !F->isDependent && !FD->getBitWidth()->isInstantiationDependent())
F->bitWidth = FD->getBitWidthValue(c->getASTContext());
if (auto alignedAttr = FD->getAttr<clang::AlignedAttr>())
F->alignAs = GetAlignAs(alignedAttr);
Class->Fields.push_back(F);
return F;
}
//-----------------------------------//
TranslationUnit* Parser::GetTranslationUnit(clang::SourceLocation Loc,
SourceLocationKind *Kind)
{
using namespace clang;
clang::SourceManager& SM = c->getSourceManager();
if (Loc.isMacroID())
Loc = SM.getExpansionLoc(Loc);
StringRef File;
auto LocKind = GetLocationKind(Loc);
switch(LocKind)
{
case SourceLocationKind::Invalid:
File = "<invalid>";
break;
case SourceLocationKind::Builtin:
File = "<built-in>";
break;
case SourceLocationKind::CommandLine:
File = "<command-line>";
break;
default:
File = SM.getFilename(Loc);
assert(!File.empty() && "Expected to find a valid file");
break;
}
if (Kind)
*Kind = LocKind;
auto Unit = opts->ASTContext->FindOrCreateModule(File.str());
Unit->originalPtr = (void*) Unit;
assert(Unit->originalPtr != nullptr);
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(const clang::Decl* D,
const clang::DeclContext *Ctx)
{
using namespace clang;
auto Context = Ctx;
// If the declaration is at global scope, just early exit.
if (Context->isTranslationUnit())
return GetTranslationUnit(D);
TranslationUnit* Unit = GetTranslationUnit(cast<Decl>(Context));
// 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<const DeclContext *, 8> ContextsTy;
ContextsTy Contexts;
for(; Context != nullptr; Context = Context->getParent())
Contexts.push_back(Context);
assert(Contexts.back()->isTranslationUnit());
Contexts.pop_back();
DeclarationContext* DC = Unit;
for (auto I = Contexts.rbegin(), E = Contexts.rend(); I != E; ++I)
{
const auto* Ctx = *I;
switch(Ctx->getDeclKind())
{
case Decl::Namespace:
{
auto ND = cast<NamespaceDecl>(Ctx);
if (ND->isAnonymousNamespace())
continue;
auto Name = ND->getName();
DC = DC->FindCreateNamespace(Name.str());
((Namespace*)DC)->isAnonymous = ND->isAnonymousNamespace();
((Namespace*)DC)->isInline = ND->isInline();
HandleDeclaration(ND, DC);
continue;
}
case Decl::LinkageSpec:
{
const LinkageSpecDecl* LD = cast<LinkageSpecDecl>(Ctx);
continue;
}
case Decl::CXXRecord:
{
auto RD = cast<CXXRecordDecl>(Ctx);
DC = WalkRecordCXX(RD);
continue;
}
case Decl::CXXDeductionGuide:
{
continue;
}
default:
{
auto D = cast<Decl>(Ctx);
auto Decl = WalkDeclaration(D);
DC = static_cast<DeclarationContext*>(Decl);
} }
}
return DC;
}
DeclarationContext* Parser::GetNamespace(const 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: return PrimitiveType::SChar;
case clang::BuiltinType::Char_S: return PrimitiveType::Char;
case clang::BuiltinType::UChar:
case clang::BuiltinType::Char_U: return PrimitiveType::UChar;
case clang::BuiltinType::WChar_S:
case clang::BuiltinType::WChar_U: return PrimitiveType::WideChar;
case clang::BuiltinType::Char16: return PrimitiveType::Char16;
case clang::BuiltinType::Char32: return PrimitiveType::Char32;
case clang::BuiltinType::Short: return PrimitiveType::Short;
case clang::BuiltinType::UShort: return PrimitiveType::UShort;
case clang::BuiltinType::Int: return PrimitiveType::Int;
case clang::BuiltinType::UInt: return PrimitiveType::UInt;
case clang::BuiltinType::Long: return PrimitiveType::Long;
case clang::BuiltinType::ULong: return PrimitiveType::ULong;
case clang::BuiltinType::LongLong: return PrimitiveType::LongLong;
case clang::BuiltinType::ULongLong: return PrimitiveType::ULongLong;
case clang::BuiltinType::Int128: return PrimitiveType::Int128;
case clang::BuiltinType::UInt128: return PrimitiveType::UInt128;
case clang::BuiltinType::Half: return PrimitiveType::Half;
case clang::BuiltinType::Float: return PrimitiveType::Float;
case clang::BuiltinType::Double: return PrimitiveType::Double;
case clang::BuiltinType::LongDouble: return PrimitiveType::LongDouble;
case clang::BuiltinType::Float128: return PrimitiveType::Float128;
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<ElaboratedTypeLoc>();
auto ITL = ETL.getNextTypeLoc();
TL = ITL;
}
else if (TypeLocClass == TypeLoc::Paren)
{
auto PTL = TL.getAs<ParenTypeLoc>();
TL = PTL.getNextTypeLoc();
}
assert(TL.getTypeLocClass() == Class);
return TL;
}
static FriendKind ConvertFriendKind(clang::Decl::FriendObjectKind FK)
{
using namespace clang;
switch (FK)
{
case Decl::FriendObjectKind::FOK_Declared:
return FriendKind::Declared;
case Decl::FriendObjectKind::FOK_Undeclared:
return FriendKind::Undeclared;
default:
return FriendKind::None;
}
}
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;
default:
return CallingConvention::Unknown;
}
}
static ExceptionSpecType ConvertExceptionType(clang::ExceptionSpecificationType EST)
{
using namespace clang;
switch (EST)
{
case ExceptionSpecificationType::EST_BasicNoexcept:
return ExceptionSpecType::BasicNoexcept;
case ExceptionSpecificationType::EST_DependentNoexcept:
return ExceptionSpecType::DependentNoexcept;
case ExceptionSpecificationType::EST_NoexceptFalse:
return ExceptionSpecType::NoexceptFalse;
case ExceptionSpecificationType::EST_NoexceptTrue:
return ExceptionSpecType::NoexceptTrue;
case ExceptionSpecificationType::EST_Dynamic:
return ExceptionSpecType::Dynamic;
case ExceptionSpecificationType::EST_DynamicNone:
return ExceptionSpecType::DynamicNone;
case ExceptionSpecificationType::EST_MSAny:
return ExceptionSpecType::MSAny;
case ExceptionSpecificationType::EST_Unevaluated:
return ExceptionSpecType::Unevaluated;
case ExceptionSpecificationType::EST_Uninstantiated:
return ExceptionSpecType::Uninstantiated;
case ExceptionSpecificationType::EST_Unparsed:
return ExceptionSpecType::Unparsed;
default:
return ExceptionSpecType::None;
}
}
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");
}
static const clang::Type* GetFinalType(const clang::Type* Ty)
{
auto FinalType = Ty;
while (true)
{
FinalType = FinalType->getUnqualifiedDesugaredType();
if (FinalType->getPointeeType().isNull())
return FinalType;
FinalType = FinalType->getPointeeType().getTypePtr();
}
}
Type* Parser::WalkType(clang::QualType QualType, const clang::TypeLoc* TL,
bool DesugarType)
{
using namespace clang;
if (QualType.isNull())
return nullptr;
auto LocValid = TL && !TL->isNull();
const clang::Type* Type = QualType.getTypePtr();
auto& AST = c->getASTContext();
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::Atomic:
{
auto Atomic = Type->getAs<clang::AtomicType>();
assert(Atomic && "Expected an atomic type");
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
Ty = WalkType(Atomic->getValueType(), &Next);
break;
}
case clang::Type::Attributed:
{
auto Attributed = Type->getAs<clang::AttributedType>();
assert(Attributed && "Expected an attributed type");
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto AT = new AttributedType();
auto Modified = Attributed->getModifiedType();
AT->modified = GetQualifiedType(Modified, &Next);
auto Equivalent = Attributed->getEquivalentType();
AT->equivalent = GetQualifiedType(Equivalent, &Next);
Ty = AT;
break;
}
case clang::Type::Builtin:
{
auto Builtin = Type->getAs<clang::BuiltinType>();
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<clang::EnumType>();
EnumDecl* ED = ET->getDecl();
auto TT = new TagType();
TT->declaration = TT->declaration = WalkDeclaration(ED);
Ty = TT;
break;
}
case clang::Type::Pointer:
{
auto Pointer = Type->getAs<clang::PointerType>();
auto P = new PointerType();
P->modifier = PointerType::TypeModifier::Pointer;
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto Pointee = Pointer->getPointeeType();
P->qualifiedPointee = GetQualifiedType(Pointee, &Next);
Ty = P;
break;
}
case clang::Type::Typedef:
{
auto TT = Type->getAs<clang::TypedefType>();
auto TD = TT->getDecl();
auto TTL = TD->getTypeSourceInfo()->getTypeLoc();
auto TDD = static_cast<TypedefNameDecl*>(WalkDeclaration(TD));
auto Type = new TypedefType();
Type->declaration = TDD;
Ty = Type;
break;
}
case clang::Type::Decayed:
{
auto DT = Type->getAs<clang::DecayedType>();
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto Type = new DecayedType();
Type->decayed = GetQualifiedType(DT->getDecayedType(), &Next);
Type->original = GetQualifiedType(DT->getOriginalType(), &Next);
Type->pointee = GetQualifiedType(DT->getPointeeType(), &Next);
Ty = Type;
break;
}
case clang::Type::Elaborated:
{
auto ET = Type->getAs<clang::ElaboratedType>();
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
Ty = WalkType(ET->getNamedType(), &Next);
break;
}
case clang::Type::Record:
{
auto RT = Type->getAs<clang::RecordType>();
RecordDecl* RD = RT->getDecl();
auto TT = new TagType();
TT->declaration = WalkDeclaration(RD);
Ty = TT;
break;
}
case clang::Type::Paren:
{
auto PT = Type->getAs<clang::ParenType>();
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
Ty = WalkType(PT->getInnerType(), &Next);
break;
}
case clang::Type::ConstantArray:
{
auto AT = AST.getAsConstantArrayType(QualType);
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto A = new ArrayType();
auto ElemTy = AT->getElementType();
A->qualifiedType = GetQualifiedType(ElemTy, &Next);
A->sizeType = ArrayType::ArraySize::Constant;
A->size = AST.getConstantArrayElementCount(AT);
if (!ElemTy->isDependentType() && !opts->skipLayoutInfo)
A->elementSize = (long)AST.getTypeSize(ElemTy);
Ty = A;
break;
}
case clang::Type::IncompleteArray:
{
auto AT = AST.getAsIncompleteArrayType(QualType);
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto A = new ArrayType();
A->qualifiedType = GetQualifiedType(AT->getElementType(), &Next);
A->sizeType = ArrayType::ArraySize::Incomplete;
Ty = A;
break;
}
case clang::Type::DependentSizedArray:
{
auto AT = AST.getAsDependentSizedArrayType(QualType);
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto A = new ArrayType();
A->qualifiedType = GetQualifiedType(AT->getElementType(), &Next);
A->sizeType = ArrayType::ArraySize::Dependent;
//A->Size = AT->getSizeExpr();
Ty = A;
break;
}
case clang::Type::UnresolvedUsing:
{
auto UT = Type->getAs<clang::UnresolvedUsingType>();
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto U = new UnresolvedUsingType();
U->declaration = static_cast<UnresolvedUsingTypename*>(
WalkDeclaration(UT->getDecl()));
Ty = U;
break;
}
case clang::Type::FunctionNoProto:
{
auto FP = Type->getAs<clang::FunctionNoProtoType>();
FunctionNoProtoTypeLoc FTL;
TypeLoc RL;
TypeLoc Next;
if (LocValid)
{
while (!TL->isNull() && TL->getTypeLocClass() != TypeLoc::FunctionNoProto)
{
Next = TL->getNextTypeLoc();
TL = &Next;
}
if (!TL->isNull() && TL->getTypeLocClass() == TypeLoc::FunctionNoProto)
{
FTL = TL->getAs<FunctionNoProtoTypeLoc>();
RL = FTL.getReturnLoc();
}
}
auto F = new FunctionType();
F->returnType = GetQualifiedType(FP->getReturnType(), &RL);
F->callingConvention = ConvertCallConv(FP->getCallConv());
Ty = F;
break;
}
case clang::Type::FunctionProto:
{
auto FP = Type->getAs<clang::FunctionProtoType>();
FunctionProtoTypeLoc FTL;
TypeLoc RL;
TypeLoc Next;
clang::SourceLocation ParamStartLoc;
if (LocValid)
{
while (!TL->isNull() && TL->getTypeLocClass() != TypeLoc::FunctionProto)
{
Next = TL->getNextTypeLoc();
TL = &Next;
}
if (!TL->isNull() && TL->getTypeLocClass() == TypeLoc::FunctionProto)
{
FTL = TL->getAs<FunctionProtoTypeLoc>();
RL = FTL.getReturnLoc();
ParamStartLoc = FTL.getLParenLoc();
}
}
auto F = new FunctionType();
F->returnType = GetQualifiedType(FP->getReturnType(), &RL);
F->callingConvention = ConvertCallConv(FP->getCallConv());
F->exceptionSpecType = ConvertExceptionType(FP->getExceptionSpecType());
for (unsigned i = 0; i < FP->getNumParams(); ++i)
{
if (FTL && FTL.getParam(i))
{
auto PVD = FTL.getParam(i);
auto FA = WalkParameter(PVD, ParamStartLoc);
F->Parameters.push_back(FA);
}
else
{
auto FA = new Parameter();
auto Arg = FP->getParamType(i);
FA->name = "";
FA->qualifiedType = GetQualifiedType(Arg);
// In this case we have no valid value to use as a pointer so
// use a special value known to the managed side to make sure
// it gets ignored.
FA->originalPtr = IgnorePtr;
F->Parameters.push_back(FA);
}
}
Ty = F;
break;
}
case clang::Type::TypeOf:
{
auto TO = Type->getAs<clang::TypeOfType>();
Ty = WalkType(TO->getUnderlyingType());
break;
}
case clang::Type::TypeOfExpr:
{
auto TO = Type->getAs<clang::TypeOfExprType>();
Ty = WalkType(TO->getUnderlyingExpr()->getType());
break;
}
case clang::Type::MemberPointer:
{
auto MP = Type->getAs<clang::MemberPointerType>();
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto MPT = new MemberPointerType();
MPT->pointee = GetQualifiedType(MP->getPointeeType(), &Next);
Ty = MPT;
break;
}
case clang::Type::TemplateSpecialization:
{
auto TS = Type->getAs<clang::TemplateSpecializationType>();
auto TST = new TemplateSpecializationType();
TemplateName Name = TS->getTemplateName();
TST->_template = static_cast<Template*>(WalkDeclaration(
Name.getAsTemplateDecl()));
if (TS->isSugared())
TST->desugared = GetQualifiedType(TS->getCanonicalTypeInternal(), TL);
TypeLoc UTL, ETL, ITL;
if (LocValid)
{
auto TypeLocClass = TL->getTypeLocClass();
if (TypeLocClass == TypeLoc::Qualified)
{
UTL = TL->getUnqualifiedLoc();
TL = &UTL;
}
else if (TypeLocClass == TypeLoc::Elaborated)
{
ETL = TL->getAs<ElaboratedTypeLoc>();
ITL = ETL.getNextTypeLoc();
TL = &ITL;
}
assert(TL->getTypeLocClass() == TypeLoc::TemplateSpecialization);
}
TemplateSpecializationTypeLoc TSpecTL;
TemplateSpecializationTypeLoc *TSTL = 0;
if (LocValid)
{
TSpecTL = TL->getAs<TemplateSpecializationTypeLoc>();
TSTL = &TSpecTL;
}
ArrayRef<clang::TemplateArgument> TSArgs(TS->getArgs(), TS->getNumArgs());
TemplateArgumentList TArgs(TemplateArgumentList::OnStack, TSArgs);
TST->Arguments = WalkTemplateArgumentList(&TArgs, TSTL);
Ty = TST;
break;
}
case clang::Type::DependentTemplateSpecialization:
{
auto TS = Type->getAs<clang::DependentTemplateSpecializationType>();
auto TST = new DependentTemplateSpecializationType();
if (TS->isSugared())
TST->desugared = GetQualifiedType(TS->getCanonicalTypeInternal(), TL);
TypeLoc UTL, ETL, ITL;
if (LocValid)
{
auto TypeLocClass = TL->getTypeLocClass();
if (TypeLocClass == TypeLoc::Qualified)
{
UTL = TL->getUnqualifiedLoc();
TL = &UTL;
}
else if (TypeLocClass == TypeLoc::Elaborated)
{
ETL = TL->getAs<ElaboratedTypeLoc>();
ITL = ETL.getNextTypeLoc();
TL = &ITL;
}
assert(TL->getTypeLocClass() == TypeLoc::DependentTemplateSpecialization);
}
DependentTemplateSpecializationTypeLoc TSpecTL;
DependentTemplateSpecializationTypeLoc *TSTL = 0;
if (LocValid)
{
TSpecTL = TL->getAs<DependentTemplateSpecializationTypeLoc>();
TSTL = &TSpecTL;
}
ArrayRef<clang::TemplateArgument> TSArgs(TS->getArgs(), TS->getNumArgs());
TemplateArgumentList TArgs(TemplateArgumentList::OnStack, TSArgs);
TST->Arguments = WalkTemplateArgumentList(&TArgs, TSTL);
Ty = TST;
break;
}
case clang::Type::TemplateTypeParm:
{
auto TP = Type->getAs<TemplateTypeParmType>();
auto TPT = new CppSharp::CppParser::TemplateParameterType();
if (auto Ident = TP->getIdentifier())
TPT->parameter->name = Ident->getName().str();
TypeLoc UTL, ETL, ITL, Next;
if (LocValid)
{
auto TypeLocClass = TL->getTypeLocClass();
if (TypeLocClass == TypeLoc::Qualified)
{
UTL = TL->getUnqualifiedLoc();
TL = &UTL;
}
else if (TypeLocClass == TypeLoc::Elaborated)
{
ETL = TL->getAs<ElaboratedTypeLoc>();
ITL = ETL.getNextTypeLoc();
TL = &ITL;
}
while (TL->getTypeLocClass() != TypeLoc::TemplateTypeParm)
{
Next = TL->getNextTypeLoc();
TL = &Next;
}
assert(TL->getTypeLocClass() == TypeLoc::TemplateTypeParm);
auto TTTL = TL->getAs<TemplateTypeParmTypeLoc>();
TPT->parameter = WalkTypeTemplateParameter(TTTL.getDecl());
}
else if (TP->getDecl())
TPT->parameter = WalkTypeTemplateParameter(TP->getDecl());
TPT->depth = TP->getDepth();
TPT->index = TP->getIndex();
TPT->isParameterPack = TP->isParameterPack();
Ty = TPT;
break;
}
case clang::Type::SubstTemplateTypeParm:
{
auto TP = Type->getAs<SubstTemplateTypeParmType>();
auto TPT = new TemplateParameterSubstitutionType();
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto RepTy = TP->getReplacementType();
TPT->replacement = GetQualifiedType(RepTy, &Next);
TPT->replacedParameter = (TemplateParameterType*)
WalkType(clang::QualType(TP->getReplacedParameter(), 0), 0);
TPT->replacedParameter->parameter = WalkTypeTemplateParameter(
TP->getReplacedParameter()->getDecl());
Ty = TPT;
break;
}
case clang::Type::InjectedClassName:
{
auto ICN = Type->getAs<clang::InjectedClassNameType>();
auto ICNT = new InjectedClassNameType();
ICNT->_class = static_cast<Class*>(WalkDeclaration(
ICN->getDecl()));
ICNT->injectedSpecializationType = GetQualifiedType(
ICN->getInjectedSpecializationType());
Ty = ICNT;
break;
}
case clang::Type::DependentName:
{
auto DN = Type->getAs<clang::DependentNameType>();
auto DNT = new DependentNameType();
switch (DN->getQualifier()->getKind())
{
case clang::NestedNameSpecifier::SpecifierKind::TypeSpec:
case clang::NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate:
{
const auto& Qualifier = clang::QualType(DN->getQualifier()->getAsType(), 0);
if (LocValid)
{
const auto& DNTL = TL->getAs<DependentNameTypeLoc>();
if (!DNTL.isNull())
{
const auto& QL = DNTL.getQualifierLoc();
const auto& NNSL = QL.getTypeLoc();
DNT->qualifier = GetQualifiedType(Qualifier, &NNSL);
}
else
{
DNT->qualifier = GetQualifiedType(Qualifier, 0);
}
}
else
{
DNT->qualifier = GetQualifiedType(Qualifier, 0);
}
break;
}
default: break;
}
DNT->identifier = DN->getIdentifier()->getName().str();
Ty = DNT;
break;
}
case clang::Type::LValueReference:
{
auto LR = Type->getAs<clang::LValueReferenceType>();
auto P = new PointerType();
P->modifier = PointerType::TypeModifier::LVReference;
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto Pointee = LR->getPointeeType();
P->qualifiedPointee = GetQualifiedType(Pointee, &Next);
Ty = P;
break;
}
case clang::Type::RValueReference:
{
auto LR = Type->getAs<clang::RValueReferenceType>();
auto P = new PointerType();
P->modifier = PointerType::TypeModifier::RVReference;
TypeLoc Next;
if (LocValid) Next = TL->getNextTypeLoc();
auto Pointee = LR->getPointeeType();
P->qualifiedPointee = GetQualifiedType(Pointee, &Next);
Ty = P;
break;
}
case clang::Type::UnaryTransform:
{
auto UT = Type->getAs<clang::UnaryTransformType>();
TypeLoc Loc;
if (LocValid)
{
clang::TypeSourceInfo* TSI = TL->getAs<UnaryTransformTypeLoc>().getUnderlyingTInfo();
Loc = TSI->getTypeLoc();
}
auto UTT = new UnaryTransformType();
UTT->desugared = GetQualifiedType(UT->isSugared() ? UT->getCanonicalTypeInternal() : UT->getBaseType(), &Loc);
UTT->baseType = GetQualifiedType(UT->getBaseType(), &Loc);
Ty = UTT;
break;
}
case clang::Type::TypeClass::Using:
{
auto U = Type->getAs<clang::UsingType>();
Ty = WalkType(U->getUnderlyingType(), TL);
break;
}
case clang::Type::Vector:
{
auto V = Type->getAs<clang::VectorType>();
auto VT = new VectorType();
VT->elementType = GetQualifiedType(V->getElementType());
VT->numElements = V->getNumElements();
Ty = VT;
break;
}
case clang::Type::PackExpansion:
{
// TODO: stubbed
Ty = new PackExpansionType();
break;
}
case clang::Type::Auto:
{
auto AT = Type->getAs<clang::AutoType>();
if (AT->isSugared())
Ty = WalkType(AT->getCanonicalTypeInternal());
else
return nullptr;
break;
}
case clang::Type::Decltype:
{
auto DT = Type->getAs<clang::DecltypeType>();
Ty = WalkType(DT->getUnderlyingType(), TL);
break;
}
case clang::Type::MacroQualified:
{
auto MT = Type->getAs<clang::MacroQualifiedType>();
Ty = WalkType(MT->getUnderlyingType(), TL);
break;
}
default:
{
Debug("Unhandled type class '%s'\n", Type->getTypeClassName());
return nullptr;
} }
Ty->isDependent = Type->isDependentType();
return Ty;
}
//-----------------------------------//
Enumeration* Parser::WalkEnum(const clang::EnumDecl* ED)
{
using namespace clang;
auto NS = GetNamespace(ED);
assert(NS && "Expected a valid namespace");
auto E = NS->FindEnum(ED->getCanonicalDecl());
if (E && !E->isIncomplete)
return E;
if (!E)
{
auto Name = GetTagDeclName(ED);
if (!Name.empty())
E = NS->FindEnum(Name, /*Create=*/false);
else
{
// Enum with no identifier - try to find existing enum through enum items
for (auto it = ED->enumerator_begin(); it != ED->enumerator_end(); ++it)
{
EnumConstantDecl* ECD = (*it);
auto EnumItemName = ECD->getNameAsString();
E = NS->FindEnumWithItem(EnumItemName);
break;
}
}
}
if (E && !E->isIncomplete)
return E;
if (!E)
{
auto Name = GetTagDeclName(ED);
if (!Name.empty())
E = NS->FindEnum(Name, /*Create=*/true);
else
{
E = new Enumeration();
E->name = Name;
E->_namespace = NS;
NS->Enums.push_back(E);
}
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<BuiltinType*>(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)
{
E->Items.push_back(WalkEnumItem(*it));
}
return E;
}
Enumeration::Item* Parser::WalkEnumItem(clang::EnumConstantDecl* ECD)
{
auto EnumItem = new Enumeration::Item();
HandleDeclaration(ECD, EnumItem);
EnumItem->name = ECD->getNameAsString();
auto Value = ECD->getInitVal();
EnumItem->value = Value.isSigned() ? Value.getSExtValue()
: Value.getZExtValue();
EnumItem->_namespace = GetNamespace(ECD);
std::string Text;
if (GetDeclText(ECD->getSourceRange(), Text))
EnumItem->expression = Text;
return EnumItem;
}
//-----------------------------------//
static const clang::CodeGen::CGFunctionInfo& GetCodeGenFunctionInfo(
clang::CodeGen::CodeGenTypes* CodeGenTypes, const clang::FunctionDecl* FD)
{
auto FTy = FD->getType()->getCanonicalTypeUnqualified();
return CodeGenTypes->arrangeFreeFunctionType(
FTy.castAs<clang::FunctionProtoType>());
}
bool Parser::CanCheckCodeGenInfo(const clang::Type* Ty)
{
auto FinalType = GetFinalType(Ty);
if (FinalType->isDependentType() ||
FinalType->isInstantiationDependentType() ||
FinalType->isUndeducedType())
return false;
if (FinalType->isFunctionType())
{
auto FTy = FinalType->getAs<clang::FunctionType>();
auto CanCheck = CanCheckCodeGenInfo(FTy->getReturnType().getTypePtr());
if (!CanCheck)
return false;
if (FinalType->isFunctionProtoType())
{
auto FPTy = FinalType->getAs<clang::FunctionProtoType>();
for (const auto& ParamType : FPTy->getParamTypes())
{
auto CanCheck = CanCheckCodeGenInfo(ParamType.getTypePtr());
if (!CanCheck)
return false;
}
}
}
if (auto RT = FinalType->getAs<clang::RecordType>())
if (!HasLayout(RT->getDecl()))
return false;
// 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 (c->getTarget().getCXXABI().isMicrosoft())
{
if (auto MPT = Ty->getAs<clang::MemberPointerType>())
if (!MPT->isDependentType())
c->getSema().RequireCompleteType(clang::SourceLocation(),
clang::QualType(Ty, 0), 1);
}
return true;
}
static clang::TypeLoc DesugarTypeLoc(const clang::TypeLoc& Loc)
{
using namespace clang;
switch (Loc.getTypeLocClass())
{
case TypeLoc::TypeLocClass::Attributed:
{
auto ATL = Loc.getAs<AttributedTypeLoc>();
return ATL.getModifiedLoc();
}
case TypeLoc::TypeLocClass::Paren:
{
auto PTL = Loc.getAs<ParenTypeLoc>();
return PTL.getInnerLoc();
}
default:
break;
}
return Loc;
}
void Parser::CompleteIfSpecializationType(const clang::QualType& QualType)
{
using namespace clang;
auto Type = QualType->getUnqualifiedDesugaredType();
auto RD = Type->getAsCXXRecordDecl();
if (!RD)
RD = const_cast<CXXRecordDecl*>(Type->getPointeeCXXRecordDecl());
ClassTemplateSpecializationDecl* CTS;
if (!RD ||
!(CTS = llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)))
return;
auto existingClient = c->getSema().getDiagnostics().getClient();
std::unique_ptr<::DiagnosticConsumer> SemaDiagnostics(new ::DiagnosticConsumer());
SemaDiagnostics->Decl = CTS;
c->getSema().getDiagnostics().setClient(SemaDiagnostics.get(), false);
Scope Scope(nullptr, Scope::ScopeFlags::ClassScope, c->getSema().getDiagnostics());
c->getSema().TUScope = &Scope;
if (!CTS->isCompleteDefinition())
c->getSema().InstantiateClassTemplateSpecialization(CTS->getBeginLoc(),
CTS, clang::TemplateSpecializationKind::TSK_ImplicitInstantiation, false);
c->getSema().getDiagnostics().setClient(existingClient, false);
c->getSema().TUScope = nullptr;
auto CT = WalkClassTemplate(CTS->getSpecializedTemplate());
auto USR = GetDeclUSR(CTS);
auto TS = CT->FindSpecialization(USR);
if (TS != nullptr && TS->isIncomplete)
{
TS->isIncomplete = false;
TS->specializationKind = WalkTemplateSpecializationKind(CTS->getSpecializationKind());
WalkRecordCXX(CTS, TS);
}
}
Parameter* Parser::WalkParameter(const clang::ParmVarDecl* PVD,
const clang::SourceLocation& ParamStartLoc)
{
using namespace clang;
auto P = walkedParameters[PVD];
if (P)
return P;
P = new Parameter();
P->name = PVD->getNameAsString();
TypeLoc PTL;
if (auto TSI = PVD->getTypeSourceInfo())
PTL = TSI->getTypeLoc();
auto paramRange = PVD->getSourceRange();
paramRange.setBegin(ParamStartLoc);
HandlePreprocessedEntities(P, paramRange, MacroLocation::FunctionParameters);
const auto& Type = PVD->getOriginalType();
auto Function = PVD->getParentFunctionOrMethod();
if (Function && cast<NamedDecl>(Function)->isExternallyVisible())
CompleteIfSpecializationType(Type);
P->qualifiedType = GetQualifiedType(Type, &PTL);
P->hasDefaultValue = PVD->hasDefaultArg();
P->index = PVD->getFunctionScopeIndex();
if (PVD->hasDefaultArg() && !PVD->hasUnparsedDefaultArg())
{
if (PVD->hasUninstantiatedDefaultArg())
P->defaultArgument = WalkExpressionObsolete(PVD->getUninstantiatedDefaultArg());
else
P->defaultArgument = WalkExpressionObsolete(PVD->getDefaultArg());
}
HandleDeclaration(PVD, P);
walkedParameters[PVD] = P;
auto Context = cast<Decl>(PVD->getDeclContext());
P->_namespace = static_cast<DeclarationContext*>(WalkDeclaration(Context));
return P;
}
void Parser::SetBody(const clang::FunctionDecl* FD, Function* F)
{
F->body = GetFunctionBody(FD);
F->isInline = FD->isInlined();
if (!F->body.empty() && F->isInline)
return;
for (const auto& R : FD->redecls())
{
if (F->body.empty())
F->body = GetFunctionBody(R);
F->isInline |= R->isInlined();
if (!F->body.empty() && F->isInline)
break;
}
}
static bool IsInvalid(clang::Stmt* Body, std::unordered_set<clang::Stmt*>& Bodies)
{
using namespace clang;
if (Bodies.find(Body) != Bodies.end())
return false;
Bodies.insert(Body);
if (auto E = dyn_cast<clang::Expr>(Body))
if (E->containsErrors())
return true;
Decl* D = 0;
switch (Body->getStmtClass())
{
case clang::Stmt::StmtClass::DeclRefExprClass:
D = cast<clang::DeclRefExpr>(Body)->getDecl();
break;
case clang::Stmt::StmtClass::MemberExprClass:
D = cast<clang::MemberExpr>(Body)->getMemberDecl();
break;
default:
break;
}
if (D)
{
if (D->isInvalidDecl())
return true;
if (auto F = dyn_cast<FunctionDecl>(D))
if (IsInvalid(F->getBody(), Bodies))
return true;
}
for (auto C : Body->children())
if (IsInvalid(C, Bodies))
return true;
return false;
}
void Parser::MarkValidity(Function* F)
{
using namespace clang;
auto FD = static_cast<FunctionDecl*>(F->originalPtr);
if (!FD->isImplicit() &&
(!FD->getTemplateInstantiationPattern() || !FD->isExternallyVisible()))
return;
auto existingClient = c->getSema().getDiagnostics().getClient();
std::unique_ptr<::DiagnosticConsumer> SemaDiagnostics(new ::DiagnosticConsumer());
SemaDiagnostics->Decl = FD;
c->getSema().getDiagnostics().setClient(SemaDiagnostics.get(), false);
Scope Scope(nullptr, Scope::ScopeFlags::FnScope, c->getSema().getDiagnostics());
c->getSema().TUScope = &Scope;
c->getSema().InstantiateFunctionDefinition(FD->getBeginLoc(), FD,
/*Recursive*/true);
F->isInvalid = FD->isInvalidDecl();
if (!F->isInvalid)
{
std::unordered_set<clang::Stmt*> Bodies{ 0 };
F->isInvalid = IsInvalid(FD->getBody(), Bodies);
}
if (!F->isInvalid)
{
DeclContext* Context = FD->getDeclContext();
while (Context)
{
F->isInvalid = cast<Decl>(Context)->isInvalidDecl();
if (F->isInvalid)
break;
Context = Context->getParent();
}
}
c->getSema().getDiagnostics().setClient(existingClient, false);
c->getSema().TUScope = nullptr;
}
void Parser::WalkFunction(const clang::FunctionDecl* FD, Function* F)
{
using namespace clang;
assert(FD->getBuiltinID() == 0);
auto FT = FD->getType()->getAs<clang::FunctionType>();
auto NS = GetNamespace(FD);
assert(NS && "Expected a valid namespace");
F->name = FD->getNameAsString();
F->_namespace = NS;
F->isConstExpr = FD->isConstexpr();
F->isVariadic = FD->isVariadic();
F->isDependent = FD->isDependentContext();
F->isPure = FD->isPure();
F->isDeleted = FD->isDeleted();
F->isDefaulted = FD->isDefaulted();
SetBody(FD, F);
if (auto InstantiatedFrom = FD->getTemplateInstantiationPattern())
F->instantiatedFrom = static_cast<Function*>(WalkDeclaration(InstantiatedFrom));
auto FK = FD->getFriendObjectKind();
F->friendKind = ConvertFriendKind(FK);
auto CC = FT->getCallConv();
F->callingConvention = ConvertCallConv(CC);
F->operatorKind = GetOperatorKindFromDecl(FD->getDeclName());
TypeLoc RTL;
FunctionTypeLoc FTL;
if (auto TSI = FD->getTypeSourceInfo())
{
auto Loc = DesugarTypeLoc(TSI->getTypeLoc());
FTL = Loc.getAs<FunctionTypeLoc>();
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 ReturnType = FD->getReturnType();
if (FD->isExternallyVisible())
CompleteIfSpecializationType(ReturnType);
F->returnType = GetQualifiedType(ReturnType, &RTL);
const auto& Mangled = GetDeclMangledName(FD);
F->mangled = Mangled;
const auto& Body = GetFunctionBody(FD);
F->body = Body;
clang::SourceLocation ParamStartLoc = FD->getBeginLoc();
clang::SourceLocation ResultLoc;
auto FTSI = FD->getTypeSourceInfo();
if (FTSI)
{
auto FTL = FTSI->getTypeLoc();
while (FTL && !FTL.getAs<FunctionTypeLoc>())
FTL = FTL.getNextTypeLoc();
if (FTL)
{
auto FTInfo = FTL.castAs<FunctionTypeLoc>();
assert(!FTInfo.isNull());
ParamStartLoc = FTInfo.getLParenLoc();
ResultLoc = FTInfo.getReturnLoc().getBeginLoc();
}
}
clang::SourceLocation BeginLoc = FD->getBeginLoc();
if (ResultLoc.isValid())
BeginLoc = ResultLoc;
clang::SourceRange Range(BeginLoc, FD->getEndLoc());
std::string Sig;
if (GetDeclText(Range, Sig))
F->signature = Sig;
for (auto VD : FD->parameters())
{
auto P = WalkParameter(VD, ParamStartLoc);
F->Parameters.push_back(P);
ParamStartLoc = VD->getEndLoc();
}
if (!opts->skipFunctionBodies && FD->hasBody())
{
if (auto Body = FD->getBody())
F->bodyStmt = WalkStatement(Body);
}
auto& CXXABI = codeGenTypes->getCXXABI();
bool HasThisReturn = false;
if (auto CD = dyn_cast<CXXConstructorDecl>(FD))
HasThisReturn = CXXABI.HasThisReturn(GlobalDecl(CD, Ctor_Complete));
else if (auto DD = dyn_cast<CXXDestructorDecl>(FD))
HasThisReturn = CXXABI.HasThisReturn(GlobalDecl(DD, Dtor_Complete));
else
HasThisReturn = CXXABI.HasThisReturn(FD);
F->hasThisReturn = HasThisReturn;
if (auto FTSI = FD->getTemplateSpecializationInfo())
F->specializationInfo = WalkFunctionTemplateSpec(FTSI, F);
MarkValidity(F);
F->qualifiedType = GetQualifiedType(FD->getType(), &FTL);
const CXXMethodDecl* MD;
if (FD->isDependentContext() ||
((MD = dyn_cast<CXXMethodDecl>(FD)) && !MD->isStatic() &&
!HasLayout(cast<CXXRecordDecl>(MD->getDeclContext()))) ||
!CanCheckCodeGenInfo(FD->getReturnType().getTypePtr()) ||
std::any_of(FD->parameters().begin(), FD->parameters().end(),
[this](auto* P) { return !CanCheckCodeGenInfo(P->getType().getTypePtr()); }))
{
return;
}
auto& CGInfo = GetCodeGenFunctionInfo(codeGenTypes.get(), FD);
F->isReturnIndirect = CGInfo.getReturnInfo().isIndirect() ||
CGInfo.getReturnInfo().isInAlloca();
unsigned Index = 0;
for (const auto& Arg : CGInfo.arguments())
{
F->Parameters[Index++]->isIndirect =
Arg.info.isIndirect() && !Arg.info.getIndirectByVal();
}
}
Function* Parser::WalkFunction(const clang::FunctionDecl* FD)
{
using namespace clang;
assert (FD->getBuiltinID() == 0);
auto NS = GetNamespace(FD);
assert(NS && "Expected a valid namespace");
auto USR = GetDeclUSR(FD);
auto F = NS->FindFunction(USR);
if (F != nullptr)
return F;
F = new Function();
HandleDeclaration(FD, F);
NS->Functions.push_back(F);
WalkFunction(FD, F);
return F;
}
//-----------------------------------//
SourceLocationKind Parser::GetLocationKind(const clang::SourceLocation& Loc)
{
using namespace clang;
clang::SourceManager& SM = c->getSourceManager();
clang::PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid())
return SourceLocationKind::Invalid;
const char *FileName = PLoc.getFilename();
if(strcmp(FileName, "<built-in>") == 0)
return SourceLocationKind::Builtin;
if(strcmp(FileName, "<command line>") == 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(clang::TranslationUnitDecl* TU)
{
for (auto D : TU->decls())
{
if (D->getBeginLoc().isValid() &&
!c->getSourceManager().isInSystemHeader(D->getBeginLoc()))
WalkDeclarationDef(D);
}
}
//-----------------------------------//
void Parser::WalkVariable(const clang::VarDecl* VD, Variable* Var)
{
HandleDeclaration(VD, Var);
Var->isConstExpr = VD->isConstexpr();
Var->name = VD->getName().str();
Var->access = ConvertToAccess(VD->getAccess());
auto Init = VD->getAnyInitializer();
Var->initializer = (Init && !Init->getType()->isDependentType()) ?
WalkVariableInitializerExpression(Init) : nullptr;
auto TL = VD->getTypeSourceInfo()->getTypeLoc();
Var->qualifiedType = GetQualifiedType(VD->getType(), &TL);
auto Mangled = GetDeclMangledName(VD);
Var->mangled = Mangled;
}
Variable* Parser::WalkVariable(const clang::VarDecl *VD)
{
using namespace clang;
auto NS = GetNamespace(VD);
assert(NS && "Expected a valid namespace");
auto USR = GetDeclUSR(VD);
if (auto Var = NS->FindVariable(USR))
return Var;
auto Var = new Variable();
Var->_namespace = NS;
WalkVariable(VD, Var);
NS->Variables.push_back(Var);
return Var;
}
//-----------------------------------//
Friend* Parser::WalkFriend(const clang::FriendDecl *FD)
{
using namespace clang;
auto NS = GetNamespace(FD);
assert(NS && "Expected a valid namespace");
auto FriendDecl = FD->getFriendDecl();
// Work around clangIndex's lack of USR handling for friends and pass the
// pointed to friend declaration instead.
auto USR = GetDeclUSR(FriendDecl ? ((Decl*)FriendDecl) : FD);
if (auto F = NS->FindFriend(USR))
return F;
auto F = new Friend();
HandleDeclaration(FD, F);
F->_namespace = NS;
if (FriendDecl)
{
F->declaration = GetDeclarationFromFriend(FriendDecl);
}
NS->Friends.push_back(F);
return F;
}
//-----------------------------------//
bool Parser::GetDeclText(clang::SourceRange SR, std::string& Text)
{
using namespace clang;
clang::SourceManager& SM = c->getSourceManager();
const LangOptions &LangOpts = c->getLangOpts();
auto Range = CharSourceRange::getTokenRange(SR);
bool Invalid;
Text = Lexer::getSourceText(Range, SM, LangOpts, &Invalid).str();
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 ME = cast<clang::MacroExpansion>(PPEntity);
auto Expansion = new MacroExpansion();
auto MD = ME->getDefinition();
if (MD && MD->getKind() != clang::PreprocessedEntity::InvalidKind)
Expansion->definition = (MacroDefinition*)
WalkPreprocessedEntity(Decl, ME->getDefinition());
Entity = Expansion;
std::string Text;
GetDeclText(PPEntity->getSourceRange(), Text);
static_cast<MacroExpansion*>(Entity)->text = Text;
break;
}
case clang::PreprocessedEntity::MacroDefinitionKind:
{
auto MD = cast<clang::MacroDefinitionRecord>(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())
break;
clang::SourceManager& SM = c->getSourceManager();
const LangOptions &LangOpts = c->getLangOpts();
auto Loc = MI->getDefinitionLoc();
if (!IsValidDeclaration(Loc))
break;
clang::SourceLocation BeginExpr =
Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
auto Range = clang::CharSourceRange::getTokenRange(
BeginExpr, MI->getDefinitionEndLoc());
bool Invalid;
StringRef Expression = Lexer::getSourceText(Range, SM, LangOpts,
&Invalid);
if (Invalid || Expression.empty())
break;
auto Definition = new MacroDefinition();
Definition->lineNumberStart = SM.getExpansionLineNumber(MD->getLocation());
Definition->lineNumberEnd = SM.getExpansionLineNumber(MD->getLocation());
Entity = Definition;
Definition->name = II->getName().trim().str();
Definition->expression = Expression.trim().str();
}
case clang::PreprocessedEntity::InclusionDirectiveKind:
// nothing to be done for InclusionDirectiveKind
break;
default:
llvm_unreachable("Unknown PreprocessedEntity");
}
if (!Entity)
return nullptr;
Entity->originalPtr = PPEntity;
auto Namespace = GetTranslationUnit(PPEntity->getSourceRange().getBegin());
if (Decl->kind == CppSharp::CppParser::AST::DeclarationKind::TranslationUnit)
{
Namespace->PreprocessedEntities.push_back(Entity);
}
else
{
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);
}
}
AST::ExpressionObsolete* Parser::WalkExpressionObsolete(const clang::Expr* Expr)
{
using namespace clang;
switch (Expr->getStmtClass())
{
case clang::Stmt::BinaryOperatorClass:
{
auto BinaryOperator = cast<clang::BinaryOperator>(Expr);
return new AST::BinaryOperatorObsolete(GetStringFromStatement(Expr),
WalkExpressionObsolete(BinaryOperator->getLHS()), WalkExpressionObsolete(BinaryOperator->getRHS()),
BinaryOperator->getOpcodeStr().str());
}
case clang::Stmt::CallExprClass:
{
auto CallExpr = cast<clang::CallExpr>(Expr);
auto CallExpression = new AST::CallExprObsolete(GetStringFromStatement(Expr),
CallExpr->getCalleeDecl() ? WalkDeclaration(CallExpr->getCalleeDecl()) : 0);
for (auto arg : CallExpr->arguments())
{
CallExpression->Arguments.push_back(WalkExpressionObsolete(arg));
}
return CallExpression;
}
case clang::Stmt::DeclRefExprClass:
return new AST::ExpressionObsolete(GetStringFromStatement(Expr), StatementClassObsolete::DeclRefExprClass,
WalkDeclaration(cast<clang::DeclRefExpr>(Expr)->getDecl()));
case clang::Stmt::CStyleCastExprClass:
case clang::Stmt::CXXConstCastExprClass:
case clang::Stmt::CXXDynamicCastExprClass:
case clang::Stmt::CXXFunctionalCastExprClass:
case clang::Stmt::CXXReinterpretCastExprClass:
case clang::Stmt::CXXStaticCastExprClass:
case clang::Stmt::ImplicitCastExprClass:
return WalkExpressionObsolete(cast<clang::CastExpr>(Expr)->getSubExprAsWritten());
case clang::Stmt::CXXOperatorCallExprClass:
{
auto OperatorCallExpr = cast<clang::CXXOperatorCallExpr>(Expr);
return new AST::ExpressionObsolete(GetStringFromStatement(Expr), StatementClassObsolete::CXXOperatorCallExpr,
OperatorCallExpr->getCalleeDecl() ? WalkDeclaration(OperatorCallExpr->getCalleeDecl()) : 0);
}
case clang::Stmt::CXXConstructExprClass:
case clang::Stmt::CXXTemporaryObjectExprClass:
{
auto ConstructorExpr = cast<clang::CXXConstructExpr>(Expr);
if (ConstructorExpr->getNumArgs() == 1)
{
auto Arg = ConstructorExpr->getArg(0);
auto TemporaryExpr = dyn_cast<clang::MaterializeTemporaryExpr>(Arg);
if (TemporaryExpr)
{
auto SubTemporaryExpr = TemporaryExpr->getSubExpr();
auto Cast = dyn_cast<clang::CastExpr>(SubTemporaryExpr);
if (!Cast ||
(Cast->getSubExprAsWritten()->getStmtClass() != clang::Stmt::IntegerLiteralClass &&
Cast->getSubExprAsWritten()->getStmtClass() != clang::Stmt::CXXNullPtrLiteralExprClass))
return WalkExpressionObsolete(SubTemporaryExpr);
return new AST::CXXConstructExprObsolete(GetStringFromStatement(Expr),
WalkDeclaration(ConstructorExpr->getConstructor()));
}
}
auto ConstructorExpression = new AST::CXXConstructExprObsolete(GetStringFromStatement(Expr),
WalkDeclaration(ConstructorExpr->getConstructor()));
for (auto arg : ConstructorExpr->arguments())
{
ConstructorExpression->Arguments.push_back(WalkExpressionObsolete(arg));
}
return ConstructorExpression;
}
case clang::Stmt::CXXBindTemporaryExprClass:
return WalkExpressionObsolete(cast<clang::CXXBindTemporaryExpr>(Expr)->getSubExpr());
case clang::Stmt::CXXDefaultArgExprClass:
return WalkExpressionObsolete(cast<clang::CXXDefaultArgExpr>(Expr)->getExpr());
case clang::Stmt::MaterializeTemporaryExprClass:
return WalkExpressionObsolete(cast<clang::MaterializeTemporaryExpr>(Expr)->getSubExpr());
default:
break;
}
if (!Expr->isValueDependent())
{
clang::Expr::EvalResult integer;
if (Expr->getStmtClass() == clang::Stmt::CharacterLiteralClass)
{
auto result = GetStringFromStatement(Expr);
if (!result.empty() &&
result.front() != '\'' &&
Expr->EvaluateAsInt(integer, c->getASTContext()))
{
result = llvm::toString(integer.Val.getInt(), 10);
}
return new AST::ExpressionObsolete(result);
}
else if (Expr->getStmtClass() != clang::Stmt::CXXBoolLiteralExprClass &&
Expr->getStmtClass() != clang::Stmt::UnaryExprOrTypeTraitExprClass &&
Expr->EvaluateAsInt(integer, c->getASTContext())
)
{
return new AST::ExpressionObsolete(llvm::toString(integer.Val.getInt(), 10));
}
}
return new AST::ExpressionObsolete(GetStringFromStatement(Expr));
}
AST::ExpressionObsolete* Parser::WalkVariableInitializerExpression(const clang::Expr* Expr)
{
using namespace clang;
if (IsCastStmt(Expr->getStmtClass()))
return WalkVariableInitializerExpression(cast<clang::CastExpr>(Expr)->getSubExprAsWritten());
if (IsLiteralStmt(Expr->getStmtClass()))
return WalkExpressionObsolete(Expr);
clang::Expr::EvalResult result;
if (!Expr->isValueDependent() &&
Expr->EvaluateAsConstantExpr(result, c->getASTContext()))
{
std::string s;
llvm::raw_string_ostream out(s);
APValuePrinter printer{c->getASTContext(), out};
if (printer.Print(result.Val, Expr->getType()))
return new AST::ExpressionObsolete(out.str());
}
return WalkExpressionObsolete(Expr);
}
bool Parser::IsCastStmt(clang::Stmt::StmtClass stmt)
{
switch (stmt)
{
case clang::Stmt::CStyleCastExprClass:
case clang::Stmt::CXXConstCastExprClass:
case clang::Stmt::CXXDynamicCastExprClass:
case clang::Stmt::CXXFunctionalCastExprClass:
case clang::Stmt::CXXReinterpretCastExprClass:
case clang::Stmt::CXXStaticCastExprClass:
case clang::Stmt::ImplicitCastExprClass:
return true;
default:
return false;
}
}
bool Parser::IsLiteralStmt(clang::Stmt::StmtClass stmt)
{
switch (stmt)
{
case clang::Stmt::CharacterLiteralClass:
case clang::Stmt::FixedPointLiteralClass:
case clang::Stmt::FloatingLiteralClass:
case clang::Stmt::IntegerLiteralClass:
case clang::Stmt::StringLiteralClass:
case clang::Stmt::ImaginaryLiteralClass:
case clang::Stmt::UserDefinedLiteralClass:
case clang::Stmt::CXXNullPtrLiteralExprClass:
case clang::Stmt::CXXBoolLiteralExprClass:
return true;
default:
return false;
}
}
std::string Parser::GetStringFromStatement(const clang::Stmt* Statement)
{
using namespace clang;
PrintingPolicy Policy(c->getLangOpts());
std::string s;
llvm::raw_string_ostream as(s);
Statement->printPretty(as, 0, Policy);
return as.str();
}
std::string Parser::GetFunctionBody(const clang::FunctionDecl* FD)
{
if (!FD->getBody())
return "";
clang::PrintingPolicy Policy(c->getLangOpts());
std::string s;
llvm::raw_string_ostream as(s);
FD->getBody()->printPretty(as, 0, Policy);
return as.str();
}
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 PPEntity : Range)
{
auto Entity = WalkPreprocessedEntity(Decl, PPEntity);
if (!Entity) continue;
if (Entity->macroLocation == MacroLocation::Unknown)
Entity->macroLocation = macroLocation;
}
}
void Parser::HandleOriginalText(const 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.str();
}
void Parser::HandleDeclaration(const clang::Decl* D, Declaration* Decl)
{
if (Decl->originalPtr != nullptr)
return;
Decl->originalPtr = (void*) D;
Decl->USR = GetDeclUSR(D);
Decl->isImplicit = D->isImplicit();
Decl->location = SourceLocation(D->getLocation().getRawEncoding());
auto IsDeclExplicit = IsExplicit(D);
if (IsDeclExplicit)
{
Decl->lineNumberStart = c->getSourceManager().getExpansionLineNumber(D->getBeginLoc());
Decl->lineNumberEnd = c->getSourceManager().getExpansionLineNumber(D->getEndLoc());
}
else
{
Decl->lineNumberStart = -1;
Decl->lineNumberEnd = -1;
}
if (Decl->PreprocessedEntities.empty() && !D->isImplicit())
{
if (clang::dyn_cast<clang::TranslationUnitDecl>(D))
{
HandlePreprocessedEntities(Decl);
}
else if (clang::dyn_cast<clang::ParmVarDecl>(D))
{
// Ignore function parameters as we already walk their preprocessed entities.
}
else if (IsDeclExplicit)
{
auto startLoc = GetDeclStartLocation(c.get(), D);
auto endLoc = D->getEndLoc();
auto range = clang::SourceRange(startLoc, endLoc);
HandlePreprocessedEntities(Decl, range);
}
}
if (IsDeclExplicit)
HandleOriginalText(D, Decl);
HandleComments(D, Decl);
if (const clang::ValueDecl *VD = clang::dyn_cast_or_null<clang::ValueDecl>(D))
Decl->isDependent = VD->getType()->isDependentType();
if (const clang::DeclContext *DC = clang::dyn_cast_or_null<clang::DeclContext>(D))
Decl->isDependent |= DC->isDependentContext();
Decl->access = ConvertToAccess(D->getAccess());
}
//-----------------------------------//
Declaration* Parser::WalkDeclarationDef(clang::Decl* D)
{
auto Decl = WalkDeclaration(D);
if (!Decl || Decl->definitionOrder > 0)
return Decl;
// 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.
clang::RecordDecl* RecordDecl;
if ((RecordDecl = llvm::dyn_cast<clang::RecordDecl>(D)) &&
RecordDecl->isCompleteDefinition())
Decl->definitionOrder = index++;
return Decl;
}
Declaration* Parser::WalkDeclaration(const clang::Decl* D)
{
using namespace clang;
if (D == nullptr)
return nullptr;
Declaration* Decl = nullptr;
auto Kind = D->getKind();
switch(D->getKind())
{
case Decl::Record:
{
auto RD = cast<RecordDecl>(D);
Decl = WalkRecord(RD);
break;
}
case Decl::CXXRecord:
{
auto RD = cast<CXXRecordDecl>(D);
Decl = WalkRecordCXX(RD);
break;
}
case Decl::ClassTemplate:
{
auto TD = cast<ClassTemplateDecl>(D);
auto Template = WalkClassTemplate(TD);
Decl = Template;
break;
}
case Decl::ClassTemplateSpecialization:
{
auto TS = cast<ClassTemplateSpecializationDecl>(D);
auto CT = WalkClassTemplateSpecialization(TS);
Decl = CT;
break;
}
case Decl::ClassTemplatePartialSpecialization:
{
auto TS = cast<ClassTemplatePartialSpecializationDecl>(D);
auto CT = WalkClassTemplatePartialSpecialization(TS);
Decl = CT;
break;
}
case Decl::FunctionTemplate:
{
auto TD = cast<FunctionTemplateDecl>(D);
auto FT = WalkFunctionTemplate(TD);
Decl = FT;
break;
}
case Decl::VarTemplate:
{
auto TD = cast<VarTemplateDecl>(D);
auto Template = WalkVarTemplate(TD);
Decl = Template;
break;
}
case Decl::VarTemplateSpecialization:
{
auto TS = cast<VarTemplateSpecializationDecl>(D);
auto CT = WalkVarTemplateSpecialization(TS);
Decl = CT;
break;
}
case Decl::VarTemplatePartialSpecialization:
{
auto TS = cast<VarTemplatePartialSpecializationDecl>(D);
auto CT = WalkVarTemplatePartialSpecialization(TS);
Decl = CT;
break;
}
case Decl::TypeAliasTemplate:
{
auto TD = cast<TypeAliasTemplateDecl>(D);
auto TA = WalkTypeAliasTemplate(TD);
Decl = TA;
break;
}
case Decl::Enum:
{
auto ED = cast<EnumDecl>(D);
Decl = WalkEnum(ED);
break;
}
case Decl::EnumConstant:
{
auto ED = cast<EnumConstantDecl>(D);
auto E = static_cast<Enumeration*>(GetNamespace(ED));
assert(E && "Expected a valid enumeration");
Decl = E->FindItemByName(ED->getNameAsString());
break;
}
case Decl::Function:
{
auto FD = cast<FunctionDecl>(D);
// Check for and ignore built-in functions.
if (FD->getBuiltinID() != 0)
break;
Decl = WalkFunction(FD);
break;
}
case Decl::LinkageSpec:
{
auto LS = cast<LinkageSpecDecl>(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<clang::TypedefDecl>(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();
// resolve the typedef before adding it to the list otherwise it might be found and returned prematurely
// see "typedef _Aligned<16, char>::type type;" and the related classes in Common.h in the tests
Typedef->qualifiedType = GetQualifiedType(TD->getUnderlyingType(), &TTL);
AST::TypedefDecl* Existing;
// if the typedef was added along the way, the just created one is useless, delete it
if ((Existing = NS->FindTypedef(Name, /*Create=*/false)))
delete Typedef;
else
NS->Typedefs.push_back(Existing = Typedef);
Decl = Existing;
break;
}
case Decl::TypeAlias:
{
auto TD = cast<clang::TypeAliasDecl>(D);
auto NS = GetNamespace(TD);
auto Name = GetDeclName(TD);
auto TypeAlias = NS->FindTypeAlias(Name, /*Create=*/false);
if (TypeAlias) return TypeAlias;
TypeAlias = NS->FindTypeAlias(Name, /*Create=*/true);
HandleDeclaration(TD, TypeAlias);
auto TTL = TD->getTypeSourceInfo()->getTypeLoc();
// see above the case for "Typedef"
TypeAlias->qualifiedType = GetQualifiedType(TD->getUnderlyingType(), &TTL);
AST::TypeAlias* Existing;
if ((Existing = NS->FindTypeAlias(Name, /*Create=*/false)))
delete TypeAlias;
else
NS->TypeAliases.push_back(Existing = TypeAlias);
if (auto TAT = TD->getDescribedAliasTemplate())
TypeAlias->describedAliasTemplate = WalkTypeAliasTemplate(TAT);
Decl = Existing;
break;
}
case Decl::TranslationUnit:
{
Decl = GetTranslationUnit(D);
break;
}
case Decl::Namespace:
{
auto ND = cast<NamespaceDecl>(D);
for (auto D : ND->decls())
{
if (!isa<NamedDecl>(D) || IsSupported(cast<NamedDecl>(D)))
Decl = WalkDeclarationDef(D);
}
break;
}
case Decl::Var:
{
auto VD = cast<VarDecl>(D);
Decl = WalkVariable(VD);
break;
}
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion:
case Decl::CXXMethod:
{
auto MD = cast<CXXMethodDecl>(D);
Decl = WalkMethodCXX(MD);
if (Decl == nullptr)
return Decl;
auto NS = GetNamespace(MD);
Decl->_namespace = NS;
break;
}
case Decl::Field:
{
auto FD = cast<FieldDecl>(D);
auto _Class = static_cast<Class*>(WalkDeclaration(FD->getParent()));
Decl = WalkFieldCXX(FD, _Class);
break;
}
case Decl::Friend:
{
auto FD = cast<FriendDecl>(D);
Decl = WalkFriend(FD);
break;
}
case Decl::TemplateTemplateParm:
{
auto TTP = cast<TemplateTemplateParmDecl>(D);
Decl = WalkTemplateTemplateParameter(TTP);
break;
}
case Decl::TemplateTypeParm:
{
auto TTPD = cast<TemplateTypeParmDecl>(D);
Decl = WalkTypeTemplateParameter(TTPD);
break;
}
case Decl::NonTypeTemplateParm:
{
auto NTTPD = cast<NonTypeTemplateParmDecl>(D);
Decl = WalkNonTypeTemplateParameter(NTTPD);
break;
}
case Decl::UnresolvedUsingTypename:
{
auto UUTD = cast<UnresolvedUsingTypenameDecl>(D);
Decl = WalkUnresolvedUsingTypename(UUTD);
break;
}
case Decl::BuiltinTemplate:
case Decl::ClassScopeFunctionSpecialization:
case Decl::PragmaComment:
case Decl::PragmaDetectMismatch:
case Decl::Empty:
case Decl::AccessSpec:
case Decl::Using:
case Decl::UsingDirective:
case Decl::UsingShadow:
case Decl::ConstructorUsingShadow:
case Decl::UnresolvedUsingValue:
case Decl::IndirectField:
case Decl::StaticAssert:
case Decl::NamespaceAlias:
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.str().c_str(), LineNo);
break;
} };
if (Decl && D->hasAttrs())
{
for (auto it = D->attr_begin(); it != D->attr_end(); ++it)
{
Attr* Attr = (*it);
switch(Attr->getKind())
{
case clang::attr::Kind::MaxFieldAlignment:
{
auto MFA = cast<clang::MaxFieldAlignmentAttr>(Attr);
Decl->maxFieldAlignment = MFA->getAlignment() / 8; // bits to bytes.
break;
}
case clang::attr::Kind::Deprecated:
{
auto DA = cast<clang::DeprecatedAttr>(Attr);
Decl->isDeprecated = true;
break;
}
case clang::attr::Kind::Aligned:
Decl->alignAs = GetAlignAs(cast<clang::AlignedAttr>(Attr));
break;
default:
break;
}
}
}
return Decl;
}
int Parser::GetAlignAs(const clang::AlignedAttr* alignedAttr)
{
return alignedAttr->isAlignas() &&
!alignedAttr->isAlignmentErrorDependent() &&
!alignedAttr->isAlignmentDependent()
? alignedAttr->getAlignment(c->getASTContext())
: 0;
}
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().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);
}
}
void Parser::SetupLLVMCodegen()
{
// Initialize enough Clang codegen machinery so we can get at ABI details.
LLVMModule.reset(new llvm::Module("", LLVMCtx));
LLVMModule->setTargetTriple(c->getTarget().getTriple().getTriple());
LLVMModule->setDataLayout(c->getTarget().getDataLayoutString());
CGM.reset(new clang::CodeGen::CodeGenModule(c->getASTContext(),
c->getHeaderSearchOpts(), c->getPreprocessorOpts(),
c->getCodeGenOpts(), *LLVMModule, c->getDiagnostics()));
codeGenTypes.reset(new clang::CodeGen::CodeGenTypes(*CGM.get()));
}
bool Parser::SetupSourceFiles(const std::vector<std::string>& SourceFiles,
std::vector<const clang::FileEntry*>& FileEntries)
{
// Check that the file is reachable.
const clang::DirectoryLookup *Dir;
llvm::SmallVector<
std::pair<const clang::FileEntry *, const clang::DirectoryEntry *>,
0> Includers;
for (const auto& SourceFile : SourceFiles)
{
auto FileEntry = c->getPreprocessor().getHeaderSearchInfo().LookupFile(SourceFile,
clang::SourceLocation(), /*isAngled*/true,
nullptr, Dir, Includers, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
if (!FileEntry)
return false;
FileEntries.push_back(&FileEntry.getPointer()->getFileEntry());
}
// 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 source;
for (const auto& SourceFile : SourceFiles)
{
source += "#include \"" + SourceFile + "\"" + "\n";
}
source += "\0";
auto buffer = llvm::MemoryBuffer::getMemBufferCopy(source);
auto& SM = c->getSourceManager();
SM.setMainFileID(SM.createFileID(std::move(buffer)));
return true;
}
class SemaConsumer : public clang::SemaConsumer {
CppSharp::CppParser::Parser& Parser;
std::vector<const clang::FileEntry*>& FileEntries;
public:
SemaConsumer(CppSharp::CppParser::Parser& parser,
std::vector<const clang::FileEntry*>& entries)
: Parser(parser), FileEntries(entries) {}
virtual void HandleTranslationUnit(clang::ASTContext& Ctx) override;
};
void SemaConsumer::HandleTranslationUnit(clang::ASTContext& Ctx)
{
auto FileEntry = FileEntries[0];
auto FileName = FileEntry->getName();
auto Unit = Parser.opts->ASTContext->FindOrCreateModule(FileName.str());
auto TU = Ctx.getTranslationUnitDecl();
Parser.HandleDeclaration(TU, Unit);
if (Unit->originalPtr == nullptr)
Unit->originalPtr = (void*)FileEntry;
Parser.WalkAST(TU);
}
ParserResult* Parser::Parse(const std::vector<std::string>& SourceFiles)
{
assert(opts->ASTContext && "Expected a valid ASTContext");
auto res = new ParserResult();
if (SourceFiles.empty())
{
res->kind = ParserResultKind::FileNotFound;
return res;
}
Setup();
SetupLLVMCodegen();
std::vector<const clang::FileEntry*> FileEntries;
if (!SetupSourceFiles(SourceFiles, FileEntries))
{
res->kind = ParserResultKind::FileNotFound;
return res;
}
std::unique_ptr<SemaConsumer> SC(new SemaConsumer(*this, FileEntries));
c->setASTConsumer(std::move(SC));
c->createSema(clang::TU_Complete, 0);
std::unique_ptr<::DiagnosticConsumer> DiagClient(new ::DiagnosticConsumer());
c->getDiagnostics().setClient(DiagClient.get(), false);
DiagClient->BeginSourceFile(c->getLangOpts(), &c->getPreprocessor());
ParseAST(c->getSema());
DiagClient->EndSourceFile();
HandleDiagnostics(res);
if(DiagClient->getNumErrors() != 0)
{
res->kind = ParserResultKind::Error;
return res;
}
res->targetInfo = GetTargetInfo();
res->kind = ParserResultKind::Success;
return res;
}
ParserResultKind Parser::ParseArchive(const std::string& File,
llvm::object::Archive* Archive,
std::vector<CppSharp::CppParser::NativeLibrary*>& NativeLibs)
{
auto NativeLib = new NativeLibrary();
NativeLib->fileName = File;
for (const auto& Symbol : Archive->symbols())
{
llvm::StringRef SymRef = Symbol.getName();
NativeLib->Symbols.push_back(SymRef.str());
}
NativeLibs.push_back(NativeLib);
return ParserResultKind::Success;
}
static ArchType ConvertArchType(unsigned int archType)
{
switch (archType)
{
case llvm::Triple::ArchType::x86:
return ArchType::x86;
case llvm::Triple::ArchType::x86_64:
return ArchType::x86_64;
}
return ArchType::UnknownArch;
}
template<class ELFT>
static void ReadELFDependencies(const llvm::object::ELFFile<ELFT>& ELFFile, CppSharp::CppParser::NativeLibrary*& NativeLib)
{
ELFDumper<ELFT> ELFDumper(&ELFFile);
for (const auto& Dependency : ELFDumper.getNeededLibraries())
NativeLib->Dependencies.push_back(Dependency.str());
}
ParserResultKind Parser::ParseSharedLib(const std::string& File,
llvm::object::ObjectFile* ObjectFile,
std::vector<CppSharp::CppParser::NativeLibrary*>& NativeLibs)
{
auto NativeLib = new NativeLibrary();
NativeLib->fileName = File;
NativeLib->archType = ConvertArchType(ObjectFile->getArch());
NativeLibs.push_back(NativeLib);
if (ObjectFile->isELF())
{
auto IDyn = llvm::cast<llvm::object::ELFObjectFileBase>(ObjectFile)->getDynamicSymbolIterators();
for (auto it = IDyn.begin(); it != IDyn.end(); ++it)
{
std::string Sym;
llvm::raw_string_ostream SymStream(Sym);
if (it->printName(SymStream))
continue;
SymStream.flush();
if (!Sym.empty())
NativeLib->Symbols.push_back(Sym);
}
if (auto ELFObjectFile = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(ObjectFile))
{
ReadELFDependencies(ELFObjectFile->getELFFile(), NativeLib);
}
else if (auto ELFObjectFile = llvm::dyn_cast<llvm::object::ELF32BEObjectFile>(ObjectFile))
{
ReadELFDependencies(ELFObjectFile->getELFFile(), NativeLib);
}
else if (auto ELFObjectFile = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(ObjectFile))
{
ReadELFDependencies(ELFObjectFile->getELFFile(), NativeLib);
}
else if (auto ELFObjectFile = llvm::dyn_cast<llvm::object::ELF64BEObjectFile>(ObjectFile))
{
ReadELFDependencies(ELFObjectFile->getELFFile(), NativeLib);
}
return ParserResultKind::Success;
}
if (ObjectFile->isCOFF())
{
auto COFFObjectFile = static_cast<llvm::object::COFFObjectFile*>(ObjectFile);
for (const auto& ExportedSymbol : COFFObjectFile->export_directories())
{
llvm::StringRef Symbol;
if (!ExportedSymbol.getSymbolName(Symbol))
NativeLib->Symbols.push_back(Symbol.str());
}
for (const auto& ImportedSymbol : COFFObjectFile->import_directories())
{
llvm::StringRef Name;
if (!ImportedSymbol.getName(Name) && (Name.endswith(".dll") || Name.endswith(".DLL")))
NativeLib->Dependencies.push_back(Name.str());
}
return ParserResultKind::Success;
}
if (ObjectFile->isMachO())
{
auto MachOObjectFile = static_cast<llvm::object::MachOObjectFile*>(ObjectFile);
for (const auto& Load : MachOObjectFile->load_commands())
{
if (Load.C.cmd == llvm::MachO::LC_ID_DYLIB ||
Load.C.cmd == llvm::MachO::LC_LOAD_DYLIB ||
Load.C.cmd == llvm::MachO::LC_LOAD_WEAK_DYLIB ||
Load.C.cmd == llvm::MachO::LC_REEXPORT_DYLIB ||
Load.C.cmd == llvm::MachO::LC_LAZY_LOAD_DYLIB ||
Load.C.cmd == llvm::MachO::LC_LOAD_UPWARD_DYLIB)
{
auto dl = MachOObjectFile->getDylibIDLoadCommand(Load);
auto lib = llvm::sys::path::filename(Load.Ptr + dl.dylib.name);
NativeLib->Dependencies.push_back(lib.str());
}
}
// HACK: the correct way is with exported(Err) but it crashes with msvc 32
// see https://bugs.llvm.org/show_bug.cgi?id=44433
for (const auto& Symbol : MachOObjectFile->symbols())
{
if (Symbol.getName().takeError() || Symbol.getFlags().takeError())
return ParserResultKind::Error;
if ((Symbol.getFlags().get() & llvm::object::BasicSymbolRef::Flags::SF_Exported) &&
!(Symbol.getFlags().get() & llvm::object::BasicSymbolRef::Flags::SF_Undefined))
NativeLib->Symbols.push_back(Symbol.getName().get().str());
}
return ParserResultKind::Success;
}
return ParserResultKind::Error;
}
ParserResultKind Parser::ReadSymbols(llvm::StringRef File,
llvm::object::basic_symbol_iterator Begin,
llvm::object::basic_symbol_iterator End,
CppSharp::CppParser::NativeLibrary*& NativeLib)
{
auto LibName = File;
NativeLib = new NativeLibrary();
NativeLib->fileName = LibName.str();
for (auto it = Begin; it != End; ++it)
{
std::string Sym;
llvm::raw_string_ostream SymStream(Sym);
if (it->printName(SymStream))
continue;
SymStream.flush();
if (!Sym.empty())
NativeLib->Symbols.push_back(Sym);
}
return ParserResultKind::Success;
}
ParserResult* Parser::ParseLibrary(const CppLinkerOptions* Opts)
{
auto res = new ParserResult();
for (const auto& Lib : Opts->Libraries)
{
if (Lib.empty())
{
res->kind = ParserResultKind::FileNotFound;
return res;
}
std::string PrefixedLib = "lib" + Lib;
std::string FileName;
std::string FileEntry;
using namespace llvm::sys;
for (const auto& LibDir : Opts->LibraryDirs)
{
std::error_code ErrorCode;
fs::directory_iterator Dir(LibDir, ErrorCode);
for (const auto& File = Dir;
Dir != fs::directory_iterator() && !ErrorCode;
Dir = Dir.increment(ErrorCode))
{
FileName = path::filename(File->path()).str();
if (FileName == Lib ||
FileName == PrefixedLib ||
path::stem(FileName) == Lib ||
path::stem(FileName) == PrefixedLib ||
path::stem(path::stem(FileName)) == Lib ||
path::stem(path::stem(FileName)) == PrefixedLib)
{
FileEntry = File->path();
goto found;
}
}
}
if (FileEntry.empty())
{
res->kind = ParserResultKind::FileNotFound;
return res;
}
found:
auto BinaryOrErr = llvm::object::createBinary(FileEntry);
if (!BinaryOrErr)
{
auto ErrMsg = llvm::toString(BinaryOrErr.takeError());
auto Diag = ParserDiagnostic();
Diag.fileName = FileEntry;
Diag.message = ErrMsg;
Diag.level = ParserDiagnosticLevel::Error;
res->Diagnostics.push_back(Diag);
res->kind = ParserResultKind::Error;
return res;
}
auto OwningBinary = std::move(BinaryOrErr.get());
auto Bin = OwningBinary.getBinary();
if (auto Archive = llvm::dyn_cast<llvm::object::Archive>(Bin)) {
res->kind = ParseArchive(FileName, Archive, res->Libraries);
if (res->kind == ParserResultKind::Error)
return res;
}
if (auto ObjectFile = llvm::dyn_cast<llvm::object::ObjectFile>(Bin))
{
res->kind = ParseSharedLib(FileName, ObjectFile, res->Libraries);
if (res->kind == ParserResultKind::Error)
return res;
}
}
res->kind = ParserResultKind::Success;
return res;
}
ParserResult* Parser::Build(const CppLinkerOptions* LinkerOptions, const std::string& File, bool Last)
{
ParserResult* error = Compile(File);
if (error)
return error;
bool LinkingError = !Link(File, LinkerOptions);
if (Last)
llvm::llvm_shutdown();
auto res = new ParserResult();
HandleDiagnostics(res);
if (LinkingError)
{
ParserDiagnostic PD;
PD.level = ParserDiagnosticLevel::Error;
PD.lineNumber = PD.columnNumber = -1;
res->addDiagnostics(PD);
}
return res;
}
ParserResult* ClangParser::ParseHeader(CppParserOptions* Opts)
{
if (!Opts)
return nullptr;
auto& Headers = Opts->SourceFiles;
if (Opts->unityBuild)
{
Parser parser(Opts);
return parser.Parse(Headers);
}
ParserResult* res = 0;
std::vector<Parser*> parsers;
for (size_t i = 0; i < Headers.size(); i++)
{
auto parser = new Parser(Opts);
parsers.push_back(parser);
std::vector<std::string> Header{Headers[i]};
if (i < Headers.size() - 1)
delete parser->Parse(Header);
else
res = parser->Parse(Header);
}
for (auto parser : parsers)
delete parser;
return res;
}
ParserResult* ClangParser::ParseLibrary(CppLinkerOptions* Opts)
{
if (!Opts)
return nullptr;
return Parser::ParseLibrary(Opts);
}
ParserResult* ClangParser::Build(CppParserOptions* Opts,
const CppLinkerOptions* LinkerOptions, const std::string& File, bool Last)
{
if (!Opts)
return 0;
Parser Parser(Opts);
return Parser.Build(LinkerOptions, File, Last);
}
ParserResult* ClangParser::Compile(CppParserOptions* Opts,
const std::string& File)
{
if (!Opts)
return 0;
Parser Parser(Opts);
return Parser.Compile(File);
}
ParserResult* ClangParser::Link(CppParserOptions* Opts,
const CppLinkerOptions* LinkerOptions, const std::string& File, bool Last)
{
if (!Opts)
return 0;
Parser Parser(Opts);
bool LinkingError = !Parser.Link(File, LinkerOptions);
if (Last)
llvm::llvm_shutdown();
auto res = new ParserResult();
if (LinkingError)
{
ParserDiagnostic PD;
PD.level = ParserDiagnosticLevel::Error;
PD.lineNumber = PD.columnNumber = -1;
res->addDiagnostics(PD);
}
return res;
}
ParserResult* Parser::Compile(const std::string& File)
{
llvm::InitializeAllAsmPrinters();
llvm::StringRef Stem = llvm::sys::path::stem(File);
Setup(/* Compile */ true);
c->getDiagnostics().setClient(new ::DiagnosticConsumer());
c->getFrontendOpts().Inputs.clear();
c->getFrontendOpts().Inputs.push_back(clang::FrontendInputFile(File, clang::Language::CXX));
const llvm::Triple Triple = c->getTarget().getTriple();
llvm::StringRef Dir(llvm::sys::path::parent_path(File));
llvm::SmallString<1024> Object(Dir);
llvm::sys::path::append(Object,
(Triple.isOSWindows() ? "" : "lib") + Stem + ".o");
c->getFrontendOpts().OutputFile = std::string(Object);
llvm::LLVMContext context;
auto action = std::make_unique<clang::EmitObjAction>(&context);
if (!c->ExecuteAction(*action))
{
auto res = new ParserResult();
HandleDiagnostics(res);
return res;
}
return 0;
}
ParserTargetInfo* Parser::GetTargetInfo()
{
auto parserTargetInfo = new ParserTargetInfo();
auto& TI = c->getTarget();
parserTargetInfo->ABI = TI.getABI().str();
parserTargetInfo->char16Type = ConvertIntType(TI.getChar16Type());
parserTargetInfo->char32Type = ConvertIntType(TI.getChar32Type());
parserTargetInfo->int64Type = ConvertIntType(TI.getInt64Type());
parserTargetInfo->intMaxType = ConvertIntType(TI.getIntMaxType());
parserTargetInfo->intPtrType = ConvertIntType(TI.getIntPtrType());
parserTargetInfo->sizeType = ConvertIntType(TI.getSizeType());
parserTargetInfo->uIntMaxType = ConvertIntType(TI.getUIntMaxType());
parserTargetInfo->wCharType = ConvertIntType(TI.getWCharType());
parserTargetInfo->wIntType = ConvertIntType(TI.getWIntType());
parserTargetInfo->boolAlign = TI.getBoolAlign();
parserTargetInfo->boolWidth = TI.getBoolWidth();
parserTargetInfo->charAlign = TI.getCharAlign();
parserTargetInfo->charWidth = TI.getCharWidth();
parserTargetInfo->char16Align = TI.getChar16Align();
parserTargetInfo->char16Width = TI.getChar16Width();
parserTargetInfo->char32Align = TI.getChar32Align();
parserTargetInfo->char32Width = TI.getChar32Width();
parserTargetInfo->halfAlign = TI.getHalfAlign();
parserTargetInfo->halfWidth = TI.getHalfWidth();
parserTargetInfo->floatAlign = TI.getFloatAlign();
parserTargetInfo->floatWidth = TI.getFloatWidth();
parserTargetInfo->doubleAlign = TI.getDoubleAlign();
parserTargetInfo->doubleWidth = TI.getDoubleWidth();
parserTargetInfo->shortAlign = TI.getShortAlign();
parserTargetInfo->shortWidth = TI.getShortWidth();
parserTargetInfo->intAlign = TI.getIntAlign();
parserTargetInfo->intWidth = TI.getIntWidth();
parserTargetInfo->intMaxTWidth = TI.getIntMaxTWidth();
parserTargetInfo->longAlign = TI.getLongAlign();
parserTargetInfo->longWidth = TI.getLongWidth();
parserTargetInfo->longDoubleAlign = TI.getLongDoubleAlign();
parserTargetInfo->longDoubleWidth = TI.getLongDoubleWidth();
parserTargetInfo->longLongAlign = TI.getLongLongAlign();
parserTargetInfo->longLongWidth = TI.getLongLongWidth();
parserTargetInfo->pointerAlign = TI.getPointerAlign(0);
parserTargetInfo->pointerWidth = TI.getPointerWidth(0);
parserTargetInfo->wCharAlign = TI.getWCharAlign();
parserTargetInfo->wCharWidth = TI.getWCharWidth();
parserTargetInfo->float128Align = TI.getFloat128Align();
parserTargetInfo->float128Width = TI.getFloat128Width();
return parserTargetInfo;
}
Declaration* Parser::GetDeclarationFromFriend(clang::NamedDecl* FriendDecl)
{
Declaration* Decl = WalkDeclarationDef(FriendDecl);
if (!Decl) return nullptr;
int MinLineNumberStart = std::numeric_limits<int>::max();
int MinLineNumberEnd = std::numeric_limits<int>::max();
auto& SM = c->getSourceManager();
for (auto it = FriendDecl->redecls_begin(); it != FriendDecl->redecls_end(); it++)
{
if (it->getLocation() != FriendDecl->getLocation())
{
auto DecomposedLocStart = SM.getDecomposedLoc(it->getLocation());
int NewLineNumberStart = SM.getLineNumber(DecomposedLocStart.first, DecomposedLocStart.second);
auto DecomposedLocEnd = SM.getDecomposedLoc(it->getEndLoc());
int NewLineNumberEnd = SM.getLineNumber(DecomposedLocEnd.first, DecomposedLocEnd.second);
if (NewLineNumberStart < MinLineNumberStart)
{
MinLineNumberStart = NewLineNumberStart;
MinLineNumberEnd = NewLineNumberEnd;
}
}
}
if (MinLineNumberStart < std::numeric_limits<int>::max())
{
Decl->lineNumberStart = MinLineNumberStart;
Decl->lineNumberEnd = MinLineNumberEnd;
}
return Decl;
}