diff options
Diffstat (limited to 'lldb/source/Symbol/ClangASTContext.cpp')
-rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 2552 |
1 files changed, 2552 insertions, 0 deletions
diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp new file mode 100644 index 00000000000..be63de20c4c --- /dev/null +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -0,0 +1,2552 @@ +//===-- ClangASTContext.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangASTContext.h" + +// C Includes +// C++ Includes +#include <string> + +// Other libraries and framework includes +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTImporter.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Frontend/LangStandard.h" + +// Project includes +#include "lldb/Core/dwarf.h" + +using namespace lldb_private; +using namespace llvm; +using namespace clang; + + +static void +ParseLangArgs +( + LangOptions &Opts, + FrontendOptions::InputKind IK +) +{ + // FIXME: Cleanup per-file based stuff. + + // Set some properties which depend soley on the input kind; it would be nice + // to move these to the language standard, and have the driver resolve the + // input kind + language standard. + if (IK == FrontendOptions::IK_Asm) { + Opts.AsmPreprocessor = 1; + } else if (IK == FrontendOptions::IK_ObjC || + IK == FrontendOptions::IK_ObjCXX || + IK == FrontendOptions::IK_PreprocessedObjC || + IK == FrontendOptions::IK_PreprocessedObjCXX) { + Opts.ObjC1 = Opts.ObjC2 = 1; + } + + LangStandard::Kind LangStd = LangStandard::lang_unspecified; + + if (LangStd == LangStandard::lang_unspecified) { + // Based on the base language, pick one. + switch (IK) { + case FrontendOptions::IK_None: + case FrontendOptions::IK_AST: + assert(0 && "Invalid input kind!"); + case FrontendOptions::IK_OpenCL: + LangStd = LangStandard::lang_opencl; + break; + case FrontendOptions::IK_Asm: + case FrontendOptions::IK_C: + case FrontendOptions::IK_PreprocessedC: + case FrontendOptions::IK_ObjC: + case FrontendOptions::IK_PreprocessedObjC: + LangStd = LangStandard::lang_gnu99; + break; + case FrontendOptions::IK_CXX: + case FrontendOptions::IK_PreprocessedCXX: + case FrontendOptions::IK_ObjCXX: + case FrontendOptions::IK_PreprocessedObjCXX: + LangStd = LangStandard::lang_gnucxx98; + break; + } + } + + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + Opts.BCPLComment = Std.hasBCPLComments(); + Opts.C99 = Std.isC99(); + Opts.CPlusPlus = Std.isCPlusPlus(); + Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.Digraphs = Std.hasDigraphs(); + Opts.GNUMode = Std.isGNUMode(); + Opts.GNUInline = !Std.isC99(); + Opts.HexFloats = Std.hasHexFloats(); + Opts.ImplicitInt = Std.hasImplicitInt(); + + // OpenCL has some additional defaults. + if (LangStd == LangStandard::lang_opencl) { + Opts.OpenCL = 1; + Opts.AltiVec = 1; + Opts.CXXOperatorNames = 1; + Opts.LaxVectorConversions = 1; + } + + // OpenCL and C++ both have bool, true, false keywords. + Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + +// if (Opts.CPlusPlus) +// Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names); +// +// if (Args.hasArg(OPT_fobjc_gc_only)) +// Opts.setGCMode(LangOptions::GCOnly); +// else if (Args.hasArg(OPT_fobjc_gc)) +// Opts.setGCMode(LangOptions::HybridGC); +// +// if (Args.hasArg(OPT_print_ivar_layout)) +// Opts.ObjCGCBitmapPrint = 1; +// +// if (Args.hasArg(OPT_faltivec)) +// Opts.AltiVec = 1; +// +// if (Args.hasArg(OPT_pthread)) +// Opts.POSIXThreads = 1; +// +// llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility, +// "default"); +// if (Vis == "default") + Opts.setVisibilityMode(LangOptions::Default); +// else if (Vis == "hidden") +// Opts.setVisibilityMode(LangOptions::Hidden); +// else if (Vis == "protected") +// Opts.setVisibilityMode(LangOptions::Protected); +// else +// Diags.Report(diag::err_drv_invalid_value) +// << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + +// Opts.OverflowChecking = Args.hasArg(OPT_ftrapv); + + // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs + // is specified, or -std is set to a conforming mode. + Opts.Trigraphs = !Opts.GNUMode; +// if (Args.hasArg(OPT_trigraphs)) +// Opts.Trigraphs = 1; +// +// Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers, +// OPT_fno_dollars_in_identifiers, +// !Opts.AsmPreprocessor); +// Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); +// Opts.Microsoft = Args.hasArg(OPT_fms_extensions); +// Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); +// if (Args.hasArg(OPT_fno_lax_vector_conversions)) +// Opts.LaxVectorConversions = 0; +// Opts.Exceptions = Args.hasArg(OPT_fexceptions); +// Opts.RTTI = !Args.hasArg(OPT_fno_rtti); +// Opts.Blocks = Args.hasArg(OPT_fblocks); +// Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); +// Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); +// Opts.Freestanding = Args.hasArg(OPT_ffreestanding); +// Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; +// Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); +// Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); +// Opts.AccessControl = Args.hasArg(OPT_faccess_control); +// Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); +// Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno); +// Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99, +// Diags); +// Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); +// Opts.ObjCConstantStringClass = getLastArgValue(Args, +// OPT_fconstant_string_class); +// Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); +// Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); +// Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); +// Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); +// Opts.Static = Args.hasArg(OPT_static_define); + Opts.OptimizeSize = 0; + + // FIXME: Eliminate this dependency. +// unsigned Opt = +// Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags); +// Opts.Optimize = Opt != 0; + unsigned Opt = 0; + + // This is the __NO_INLINE__ define, which just depends on things like the + // optimization level and -fno-inline, not actually whether the backend has + // inlining enabled. + // + // FIXME: This is affected by other options (-fno-inline). + Opts.NoInline = !Opt; + +// unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags); +// switch (SSP) { +// default: +// Diags.Report(diag::err_drv_invalid_value) +// << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; +// break; +// case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break; +// case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break; +// case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break; +// } +} + +//---------------------------------------------------------------------- +// ClangASTContext constructor +//---------------------------------------------------------------------- +//ClangASTContext::ClangASTContext(Module *module) : +// m_target_triple(), +// m_ast_context_ap(), +// m_language_options_ap(), +// m_source_manager_ap(), +// m_target_info_ap(), +// m_identifier_table_ap(), +// m_selector_table_ap(), +// m_builtins_ap() +//{ +// if (module) +// { +// ObjectFile * objfile = module->GetObjectFile(); +// if (objfile) +// objfile->GetTargetTriple(m_target_triple); +// } +//} + +//ClangASTContext::ClangASTContext(const ConstString& target_triple) : +// m_target_triple(target_triple), +// m_ast_context_ap(), +// m_language_options_ap(), +// m_source_manager_ap(), +// m_target_info_ap(), +// m_identifier_table_ap(), +// m_selector_table_ap(), +// m_builtins_ap() +//{ +//} +ClangASTContext::ClangASTContext(const char *target_triple) : + m_target_triple(), + m_ast_context_ap(), + m_language_options_ap(), + m_source_manager_ap(), + m_diagnostic_ap(), + m_target_options_ap(), + m_target_info_ap(), + m_identifier_table_ap(), + m_selector_table_ap(), + m_builtins_ap() +{ + if (target_triple && target_triple[0]) + m_target_triple.assign (target_triple); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ClangASTContext::~ClangASTContext() +{ + m_builtins_ap.reset(); + m_selector_table_ap.reset(); + m_identifier_table_ap.reset(); + m_target_info_ap.reset(); + m_target_options_ap.reset(); + m_diagnostic_ap.reset(); + m_source_manager_ap.reset(); + m_language_options_ap.reset(); + m_ast_context_ap.reset(); +} + + +void +ClangASTContext::Clear() +{ + m_ast_context_ap.reset(); + m_language_options_ap.reset(); + m_source_manager_ap.reset(); + m_diagnostic_ap.reset(); + m_target_options_ap.reset(); + m_target_info_ap.reset(); + m_identifier_table_ap.reset(); + m_selector_table_ap.reset(); + m_builtins_ap.reset(); +} + +const char * +ClangASTContext::GetTargetTriple () +{ + return m_target_triple.c_str(); +} + +void +ClangASTContext::SetTargetTriple (const char *target_triple) +{ + Clear(); + m_target_triple.assign(target_triple); +} + + +ASTContext * +ClangASTContext::getASTContext() +{ + if (m_ast_context_ap.get() == NULL) + { + m_ast_context_ap.reset( + new ASTContext( + *getLanguageOptions(), + *getSourceManager(), + *getTargetInfo(), + *getIdentifierTable(), + *getSelectorTable(), + *getBuiltinContext())); + } + return m_ast_context_ap.get(); +} + +Builtin::Context * +ClangASTContext::getBuiltinContext() +{ + if (m_builtins_ap.get() == NULL) + m_builtins_ap.reset (new Builtin::Context(*getTargetInfo())); + return m_builtins_ap.get(); +} + +IdentifierTable * +ClangASTContext::getIdentifierTable() +{ + if (m_identifier_table_ap.get() == NULL) + m_identifier_table_ap.reset(new IdentifierTable (*ClangASTContext::getLanguageOptions(), NULL)); + return m_identifier_table_ap.get(); +} + +LangOptions * +ClangASTContext::getLanguageOptions() +{ + if (m_language_options_ap.get() == NULL) + { + m_language_options_ap.reset(new LangOptions()); + ParseLangArgs(*m_language_options_ap, FrontendOptions::IK_ObjCXX); +// InitializeLangOptions(*m_language_options_ap, FrontendOptions::IK_ObjCXX); + } + return m_language_options_ap.get(); +} + +SelectorTable * +ClangASTContext::getSelectorTable() +{ + if (m_selector_table_ap.get() == NULL) + m_selector_table_ap.reset (new SelectorTable()); + return m_selector_table_ap.get(); +} + +SourceManager * +ClangASTContext::getSourceManager() +{ + if (m_source_manager_ap.get() == NULL) + m_source_manager_ap.reset(new SourceManager(*getDiagnostic())); + return m_source_manager_ap.get(); +} + +Diagnostic * +ClangASTContext::getDiagnostic() +{ + if (m_diagnostic_ap.get() == NULL) + m_diagnostic_ap.reset(new Diagnostic()); + return m_diagnostic_ap.get(); +} + +TargetOptions * +ClangASTContext::getTargetOptions() +{ + if (m_target_options_ap.get() == NULL && !m_target_triple.empty()) + { + m_target_options_ap.reset (new TargetOptions()); + if (m_target_options_ap.get()) + m_target_options_ap->Triple = m_target_triple; + } + return m_target_options_ap.get(); +} + + +TargetInfo * +ClangASTContext::getTargetInfo() +{ + // target_triple should be something like "x86_64-apple-darwin10" + if (m_target_info_ap.get() == NULL && !m_target_triple.empty()) + m_target_info_ap.reset (TargetInfo::CreateTargetInfo(*getDiagnostic(), *getTargetOptions())); + return m_target_info_ap.get(); +} + +#pragma mark Basic Types + +static inline bool +QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast_context, QualType qual_type) +{ + uint64_t qual_type_bit_size = ast_context->getTypeSize(qual_type); + if (qual_type_bit_size == bit_size) + return true; + return false; +} + +void * +ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (lldb::Encoding encoding, uint32_t bit_size) +{ + ASTContext *ast_context = getASTContext(); + + assert (ast_context != NULL); + + return GetBuiltinTypeForEncodingAndBitSize (ast_context, encoding, bit_size); +} + +void * +ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (clang::ASTContext *ast_context, lldb::Encoding encoding, uint32_t bit_size) +{ + if (!ast_context) + return NULL; + + switch (encoding) + { + case lldb::eEncodingInvalid: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy)) + return ast_context->VoidPtrTy.getAsOpaquePtr(); + break; + + case lldb::eEncodingUint: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) + return ast_context->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) + return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) + return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + break; + + case lldb::eEncodingSint: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) + return ast_context->ShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) + return ast_context->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) + return ast_context->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) + return ast_context->LongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) + return ast_context->Int128Ty.getAsOpaquePtr(); + break; + + case lldb::eEncodingIEEE754: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy)) + return ast_context->FloatTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy)) + return ast_context->DoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy)) + return ast_context->LongDoubleTy.getAsOpaquePtr(); + break; + + case lldb::eEncodingVector: + default: + break; + } + + return NULL; +} + +void * +ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name, uint32_t dw_ate, uint32_t bit_size) +{ + ASTContext *ast_context = getASTContext(); + + #define streq(a,b) strcmp(a,b) == 0 + assert (ast_context != NULL); + if (ast_context) + { + switch (dw_ate) + { + default: + break; + + case DW_ATE_address: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy)) + return ast_context->VoidPtrTy.getAsOpaquePtr(); + break; + + case DW_ATE_boolean: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->BoolTy)) + return ast_context->BoolTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + break; + + case DW_ATE_complex_float: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatComplexTy)) + return ast_context->FloatComplexTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleComplexTy)) + return ast_context->DoubleComplexTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleComplexTy)) + return ast_context->LongDoubleComplexTy.getAsOpaquePtr(); + break; + + case DW_ATE_float: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy)) + return ast_context->FloatTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy)) + return ast_context->DoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy)) + return ast_context->LongDoubleTy.getAsOpaquePtr(); + break; + + case DW_ATE_signed: + if (type_name) + { + if (streq(type_name, "int") || + streq(type_name, "signed int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) + return ast_context->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) + return ast_context->Int128Ty.getAsOpaquePtr(); + } + + if (streq(type_name, "long int") || + streq(type_name, "long long int") || + streq(type_name, "signed long long")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) + return ast_context->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) + return ast_context->LongLongTy.getAsOpaquePtr(); + } + + if (streq(type_name, "short") || + streq(type_name, "short int") || + streq(type_name, "signed short") || + streq(type_name, "short signed int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) + return ast_context->ShortTy.getAsOpaquePtr(); + } + + if (streq(type_name, "char") || + streq(type_name, "signed char")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) + return ast_context->SignedCharTy.getAsOpaquePtr(); + } + + if (streq(type_name, "wchar_t")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->WCharTy)) + return ast_context->WCharTy.getAsOpaquePtr(); + } + + } + // We weren't able to match up a type name, just search by size + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) + return ast_context->ShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) + return ast_context->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) + return ast_context->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) + return ast_context->LongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) + return ast_context->Int128Ty.getAsOpaquePtr(); + break; + + case DW_ATE_signed_char: + if (type_name) + { + if (streq(type_name, "signed char")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) + return ast_context->SignedCharTy.getAsOpaquePtr(); + } + } + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) + return ast_context->SignedCharTy.getAsOpaquePtr(); + break; + + case DW_ATE_unsigned: + if (type_name) + { + if (streq(type_name, "unsigned int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) + return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + } + + if (streq(type_name, "unsigned int") || + streq(type_name, "long unsigned int") || + streq(type_name, "unsigned long long")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) + return ast_context->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) + return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); + } + + if (streq(type_name, "unsigned short") || + streq(type_name, "short unsigned int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + } + if (streq(type_name, "unsigned char")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + } + + } + // We weren't able to match up a type name, just search by size + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) + return ast_context->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) + return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) + return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + break; + + case DW_ATE_unsigned_char: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + break; + + case DW_ATE_imaginary_float: + break; + } + } + // This assert should fire for anything that we don't catch above so we know + // to fix any issues we run into. + assert (!"error: ClangASTContext::GetClangTypeForDWARFEncodingAndSize() contains an unhandled encoding. Fix this ASAP!"); + return NULL; +} + +void * +ClangASTContext::GetVoidBuiltInType() +{ + return getASTContext()->VoidTy.getAsOpaquePtr(); +} + +void * +ClangASTContext::GetCStringType (bool is_const) +{ + QualType char_type(getASTContext()->CharTy); + + if (is_const) + char_type.addConst(); + + return getASTContext()->getPointerType(char_type).getAsOpaquePtr(); +} + +void * +ClangASTContext::GetVoidPtrType (bool is_const) +{ + return GetVoidPtrType(getASTContext(), is_const); +} + +void * +ClangASTContext::GetVoidPtrType (clang::ASTContext *ast_context, bool is_const) +{ + QualType void_ptr_type(ast_context->VoidPtrTy); + + if (is_const) + void_ptr_type.addConst(); + + return void_ptr_type.getAsOpaquePtr(); +} + +void * +ClangASTContext::CopyType(clang::ASTContext *dest_context, + clang::ASTContext *source_context, + void * clang_type) +{ + Diagnostic diagnostics; + FileManager file_manager; + ASTImporter importer(diagnostics, + *dest_context, file_manager, + *source_context, file_manager); + QualType ret = importer.Import(QualType::getFromOpaquePtr(clang_type)); + return ret.getAsOpaquePtr(); +} + +#pragma mark CVR modifiers + +void * +ClangASTContext::AddConstModifier (void *clang_type) +{ + if (clang_type) + { + QualType result(QualType::getFromOpaquePtr(clang_type)); + result.addConst(); + return result.getAsOpaquePtr(); + } + return NULL; +} + +void * +ClangASTContext::AddRestrictModifier (void *clang_type) +{ + if (clang_type) + { + QualType result(QualType::getFromOpaquePtr(clang_type)); + result.getQualifiers().setRestrict (true); + return result.getAsOpaquePtr(); + } + return NULL; +} + +void * +ClangASTContext::AddVolatileModifier (void *clang_type) +{ + if (clang_type) + { + QualType result(QualType::getFromOpaquePtr(clang_type)); + result.getQualifiers().setVolatile (true); + return result.getAsOpaquePtr(); + } + return NULL; +} + +#pragma mark Structure, Unions, Classes + +void * +ClangASTContext::CreateRecordType (const char *name, int kind, DeclContext *decl_ctx) +{ + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + + if (decl_ctx == NULL) + decl_ctx = ast_context->getTranslationUnitDecl(); + + // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and + // we will need to update this code. I was told to currently always use + // the CXXRecordDecl class since we often don't know from debug information + // if something is struct or a class, so we default to always use the more + // complete definition just in case. + CXXRecordDecl *decl = CXXRecordDecl::Create(*ast_context, + (TagDecl::TagKind)kind, + decl_ctx, + SourceLocation(), + name && name[0] ? &ast_context->Idents.get(name) : NULL); + + return ast_context->getTagDeclType(decl).getAsOpaquePtr(); +} + +bool +ClangASTContext::AddFieldToRecordType (void * record_clang_type, const char *name, void * field_type, int access, uint32_t bitfield_bit_size) +{ + if (record_clang_type == NULL || field_type == NULL) + return false; + + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + + assert (ast_context != NULL); + assert (identifier_table != NULL); + + QualType record_qual_type(QualType::getFromOpaquePtr(record_clang_type)); + + Type *clang_type = record_qual_type.getTypePtr(); + if (clang_type) + { + const RecordType *record_type = dyn_cast<RecordType>(clang_type); + + if (record_type) + { + RecordDecl *record_decl = record_type->getDecl(); + + CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + cxx_record_decl->setEmpty (false); + + clang::Expr *bit_width = NULL; + if (bitfield_bit_size != 0) + { + APInt bitfield_bit_size_apint(ast_context->getTypeSize(ast_context->IntTy), bitfield_bit_size); + bit_width = new (*ast_context)IntegerLiteral (bitfield_bit_size_apint, ast_context->IntTy, SourceLocation()); + } + FieldDecl *field = FieldDecl::Create(*ast_context, + record_decl, + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + QualType::getFromOpaquePtr(field_type), // Field type + NULL, // DeclaratorInfo * + bit_width, // BitWidth + false); // Mutable + + field->setAccess((AccessSpecifier)access); + + if (field) + { + record_decl->addDecl(field); + return true; + } + } + } + return false; +} + +bool +ClangASTContext::FieldIsBitfield (FieldDecl* field, uint32_t& bitfield_bit_size) +{ + return FieldIsBitfield(getASTContext(), field, bitfield_bit_size); +} + +bool +ClangASTContext::FieldIsBitfield +( + ASTContext *ast_context, + FieldDecl* field, + uint32_t& bitfield_bit_size +) +{ + if (ast_context == NULL || field == NULL) + return false; + + if (field->isBitField()) + { + Expr* bit_width_expr = field->getBitWidth(); + if (bit_width_expr) + { + llvm::APSInt bit_width_apsint; + if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, *ast_context)) + { + bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); + return true; + } + } + } + return false; +} + +bool +ClangASTContext::RecordHasFields (const RecordDecl *record_decl) +{ + if (record_decl == NULL) + return false; + + if (!record_decl->field_empty()) + return true; + + // No fields, lets check this is a CXX record and check the base classes + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + if (RecordHasFields(base_class_decl)) + return true; + } + } + return false; +} + +void +ClangASTContext::SetDefaultAccessForRecordFields (void *clang_qual_type, int default_accessibility, int *assigned_accessibilities, size_t num_assigned_accessibilities) +{ + if (clang_qual_type) + { + QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type)); + Type *clang_type = qual_type.getTypePtr(); + if (clang_type) + { + RecordType *record_type = dyn_cast<RecordType>(clang_type); + if (record_type) + { + RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) + { + uint32_t field_idx; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(), field_idx = 0; + field != field_end; + ++field, ++field_idx) + { + // If no accessibility was assigned, assign the correct one + if (field_idx < num_assigned_accessibilities && assigned_accessibilities[field_idx] == clang::AS_none) + field->setAccess ((AccessSpecifier)default_accessibility); + } + } + } + } + } +} + +#pragma mark C++ Base Classes + +CXXBaseSpecifier * +ClangASTContext::CreateBaseClassSpecifier (void *base_class_type, int access, bool is_virtual, bool base_of_class) +{ + if (base_class_type) + return new CXXBaseSpecifier(SourceRange(), is_virtual, base_of_class, (AccessSpecifier)access, QualType::getFromOpaquePtr(base_class_type)); + return NULL; +} + +bool +ClangASTContext::SetBaseClassesForClassType (void *class_clang_type, CXXBaseSpecifier const * const *base_classes, unsigned num_base_classes) +{ + if (class_clang_type) + { + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + + assert (ast_context != NULL); + assert (identifier_table != NULL); + + Type *clang_type = QualType::getFromOpaquePtr(class_clang_type).getTypePtr(); + if (clang_type) + { + RecordType *record_type = dyn_cast<RecordType>(clang_type); + if (record_type) + { + CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_type->getDecl()); + if (cxx_record_decl) + { + //cxx_record_decl->setEmpty (false); + cxx_record_decl->setBases(base_classes, num_base_classes); + return true; + } + } + } + } + return false; +} + + +#pragma mark Aggregate Types + +bool +ClangASTContext::IsAggregateType (void *clang_type) +{ + if (clang_type == NULL) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + + if (qual_type->isAggregateType ()) + return true; + + switch (qual_type->getTypeClass()) + { + case Type::IncompleteArray: + case Type::VariableArray: + case Type::ConstantArray: + case Type::ExtVector: + case Type::Vector: + case Type::Record: + return true; + + case Type::Typedef: + return ClangASTContext::IsAggregateType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr()); + + default: + break; + } + // The clang type does have a value + return false; +} + +uint32_t +ClangASTContext::GetNumChildren (void *clang_qual_type, bool omit_empty_base_classes) +{ + if (clang_qual_type == NULL) + return 0; + + uint32_t num_children = 0; + QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type)); + switch (qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + if (omit_empty_base_classes) + { + // Check each base classes to see if it or any of its + // base classes contain any fields. This can help + // limit the noise in variable views by not having to + // show base classes that contain no members. + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + + // Skip empty base classes + if (RecordHasFields(base_class_decl) == false) + continue; + + num_children++; + } + } + else + { + // Include all base classes + num_children += cxx_record_decl->getNumBases(); + } + + } + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field) + ++num_children; + } + break; + + case Type::ConstantArray: + num_children = cast<ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue(); + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(), omit_empty_base_classes); + // If this type points to a simple type, then it has 1 child + if (num_pointee_children == 0) + num_children = 1; + else + num_children = num_pointee_children; + } + break; + + case Type::Typedef: + num_children = ClangASTContext::GetNumChildren (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), omit_empty_base_classes); + break; + + default: + break; + } + return num_children; +} + + +void * +ClangASTContext::GetChildClangTypeAtIndex +( + const char *parent_name, + void *parent_clang_type, + uint32_t idx, + bool transparent_pointers, + bool omit_empty_base_classes, + std::string& child_name, + uint32_t &child_byte_size, + int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, + uint32_t &child_bitfield_bit_offset +) +{ + if (parent_clang_type) + + return GetChildClangTypeAtIndex (getASTContext(), + parent_name, + parent_clang_type, + idx, + transparent_pointers, + omit_empty_base_classes, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset); + return NULL; +} + +void * +ClangASTContext::GetChildClangTypeAtIndex +( + ASTContext *ast_context, + const char *parent_name, + void *parent_clang_type, + uint32_t idx, + bool transparent_pointers, + bool omit_empty_base_classes, + std::string& child_name, + uint32_t &child_byte_size, + int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, + uint32_t &child_bitfield_bit_offset +) +{ + if (parent_clang_type == NULL) + return NULL; + + if (idx < ClangASTContext::GetNumChildren (parent_clang_type, omit_empty_base_classes)) + { + uint32_t bit_offset; + child_bitfield_bit_size = 0; + child_bitfield_bit_offset = 0; + QualType parent_qual_type(QualType::getFromOpaquePtr(parent_clang_type)); + switch (parent_qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const ASTRecordLayout &record_layout = ast_context->getASTRecordLayout(record_decl); + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + // We might have base classes to print out first + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + const CXXRecordDecl *base_class_decl = NULL; + + // Skip empty base classes + if (omit_empty_base_classes) + { + base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + if (RecordHasFields(base_class_decl) == false) + continue; + } + + if (idx == child_idx) + { + if (base_class_decl == NULL) + base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + + + if (base_class->isVirtual()) + bit_offset = record_layout.getVBaseClassOffset(base_class_decl); + else + bit_offset = record_layout.getBaseClassOffset(base_class_decl); + + // Base classes should be a multiple of 8 bits in size + assert (bit_offset % 8 == 0); + child_byte_offset = bit_offset/8; + std::string base_class_type_name(base_class->getType().getAsString()); + + child_name.assign(base_class_type_name.c_str()); + + uint64_t clang_type_info_bit_size = ast_context->getTypeSize(base_class->getType()); + + // Base classes biut sizes should be a multiple of 8 bits in size + assert (clang_type_info_bit_size % 8 == 0); + child_byte_size = clang_type_info_bit_size / 8; + return base_class->getType().getAsOpaquePtr(); + } + // We don't increment the child index in the for loop since we might + // be skipping empty base classes + ++child_idx; + } + } + const unsigned num_fields = record_layout.getFieldCount(); + + // Make sure index is in range... + uint32_t field_idx = 0; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx) + { + if (idx == child_idx) + { + // Print the member type if requested + // Print the member name and equal sign + child_name.assign(field->getNameAsString().c_str()); + + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(field->getType()); + assert(field_idx < num_fields); + + child_byte_size = field_type_info.first / 8; + + // Figure out the field offset within the current struct/union/class type + bit_offset = record_layout.getFieldOffset (field_idx); + child_byte_offset = bit_offset / 8; + if (ClangASTContext::FieldIsBitfield (ast_context, *field, child_bitfield_bit_size)) + child_bitfield_bit_offset = bit_offset % 8; + + return field->getType().getAsOpaquePtr(); + } + } + } + break; + + case Type::ConstantArray: + { + const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr()); + const uint64_t element_count = array->getSize().getLimitedValue(); + + if (idx < element_count) + { + std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(array->getElementType()); + + char element_name[32]; + ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); + + child_name.assign(element_name); + assert(field_type_info.first % 8 == 0); + child_byte_size = field_type_info.first / 8; + child_byte_offset = idx * child_byte_size; + return array->getElementType().getAsOpaquePtr(); + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(parent_qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + + if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetChildClangTypeAtIndex (ast_context, + parent_name, + pointer_type->getPointeeType().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset); + } + else + { + if (parent_name) + { + child_name.assign(1, '*'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0) + { + std::pair<uint64_t, unsigned> clang_type_info = ast_context->getTypeInfo(pointee_type); + assert(clang_type_info.first % 8 == 0); + child_byte_size = clang_type_info.first / 8; + child_byte_offset = 0; + return pointee_type.getAsOpaquePtr(); + } + } + } + break; + + case Type::Typedef: + return GetChildClangTypeAtIndex (ast_context, + parent_name, + cast<TypedefType>(parent_qual_type)->LookThroughTypedefs().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset); + break; + + default: + break; + } + } + return false; +} + +static inline bool +BaseSpecifierIsEmpty (const CXXBaseSpecifier *b) +{ + return ClangASTContext::RecordHasFields(cast<CXXRecordDecl>(b->getType()->getAs<RecordType>()->getDecl())) == false; +} + +static uint32_t +GetNumBaseClasses (const CXXRecordDecl *cxx_record_decl, bool omit_empty_base_classes) +{ + uint32_t num_bases = 0; + if (cxx_record_decl) + { + if (omit_empty_base_classes) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + // Skip empty base classes + if (omit_empty_base_classes) + { + if (BaseSpecifierIsEmpty (base_class)) + continue; + } + ++num_bases; + } + } + else + num_bases = cxx_record_decl->getNumBases(); + } + return num_bases; +} + + +static uint32_t +GetIndexForRecordBase +( + const RecordDecl *record_decl, + const CXXBaseSpecifier *base_spec, + bool omit_empty_base_classes +) +{ + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + +// const char *super_name = record_decl->getNameAsCString(); +// const char *base_name = base_spec->getType()->getAs<RecordType>()->getDecl()->getNameAsCString(); +// printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name); +// + if (cxx_record_decl) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + if (omit_empty_base_classes) + { + if (BaseSpecifierIsEmpty (base_class)) + continue; + } + +// printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n", super_name, base_name, +// child_idx, +// base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString()); +// +// + if (base_class == base_spec) + return child_idx; + ++child_idx; + } + } + + return UINT32_MAX; +} + + +static uint32_t +GetIndexForRecordChild +( + const RecordDecl *record_decl, + NamedDecl *canonical_decl, + bool omit_empty_base_classes +) +{ + uint32_t child_idx = GetNumBaseClasses (dyn_cast<CXXRecordDecl>(record_decl), omit_empty_base_classes); + +// const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); +// +//// printf ("GetIndexForRecordChild (%s, %s)\n", record_decl->getNameAsCString(), canonical_decl->getNameAsCString()); +// if (cxx_record_decl) +// { +// CXXRecordDecl::base_class_const_iterator base_class, base_class_end; +// for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); +// base_class != base_class_end; +// ++base_class) +// { +// if (omit_empty_base_classes) +// { +// if (BaseSpecifierIsEmpty (base_class)) +// continue; +// } +// +//// printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n", +//// record_decl->getNameAsCString(), +//// canonical_decl->getNameAsCString(), +//// child_idx, +//// base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString()); +// +// +// CXXRecordDecl *curr_base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); +// if (curr_base_class_decl == canonical_decl) +// { +// return child_idx; +// } +// ++child_idx; +// } +// } +// +// const uint32_t num_bases = child_idx; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { +// printf ("GetIndexForRecordChild (%s, %s) field[%u] = %s\n", +// record_decl->getNameAsCString(), +// canonical_decl->getNameAsCString(), +// child_idx - num_bases, +// field->getNameAsCString()); + + if (field->getCanonicalDecl() == canonical_decl) + return child_idx; + } + + return UINT32_MAX; +} + +// Look for a child member (doesn't include base classes, but it does include +// their members) in the type hierarchy. Returns an index path into "clang_type" +// on how to reach the appropriate member. +// +// class A +// { +// public: +// int m_a; +// int m_b; +// }; +// +// class B +// { +// }; +// +// class C : +// public B, +// public A +// { +// }; +// +// If we have a clang type that describes "class C", and we wanted to looked +// "m_b" in it: +// +// With omit_empty_base_classes == false we would get an integer array back with: +// { 1, 1 } +// The first index 1 is the child index for "class A" within class C +// The second index 1 is the child index for "m_b" within class A +// +// With omit_empty_base_classes == true we would get an integer array back with: +// { 0, 1 } +// The first index 0 is the child index for "class A" within class C (since class B doesn't have any members it doesn't count) +// The second index 1 is the child index for "m_b" within class A + +size_t +ClangASTContext::GetIndexOfChildMemberWithName +( + ASTContext *ast_context, + void *clang_type, + const char *name, + bool omit_empty_base_classes, + std::vector<uint32_t>& child_indexes +) +{ + if (clang_type && name && name[0]) + { + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + + assert(record_decl); + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + + // Try and find a field that matches NAME + RecordDecl::field_iterator field, field_end; + StringRef name_sref(name); + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { + if (field->getName().equals (name_sref)) + { + // We have to add on the number of base classes to this index! + child_indexes.push_back (child_idx + GetNumBaseClasses (cxx_record_decl, omit_empty_base_classes)); + return child_indexes.size(); + } + } + + if (cxx_record_decl) + { + const RecordDecl *parent_record_decl = cxx_record_decl; + + //printf ("parent = %s\n", parent_record_decl->getNameAsCString()); + + //const Decl *root_cdecl = cxx_record_decl->getCanonicalDecl(); + // Didn't find things easily, lets let clang do its thang... + IdentifierInfo & ident_ref = ast_context->Idents.get(name, name + strlen (name)); + DeclarationName decl_name(&ident_ref); + + CXXBasePaths paths; + if (cxx_record_decl->lookupInBases(CXXRecordDecl::FindOrdinaryMember, + decl_name.getAsOpaquePtr(), + paths)) + { + uint32_t child_idx; + CXXBasePaths::const_paths_iterator path, path_end = paths.end(); + for (path = paths.begin(); path != path_end; ++path) + { + const size_t num_path_elements = path->size(); + for (size_t e=0; e<num_path_elements; ++e) + { + CXXBasePathElement elem = (*path)[e]; + + child_idx = GetIndexForRecordBase (parent_record_decl, elem.Base, omit_empty_base_classes); + if (child_idx == UINT32_MAX) + { + child_indexes.clear(); + return 0; + } + else + { + child_indexes.push_back (child_idx); + parent_record_decl = cast<RecordDecl>(elem.Base->getType()->getAs<RecordType>()->getDecl()); + } + } + DeclContext::lookup_iterator named_decl_pos; + for (named_decl_pos = path->Decls.first; + named_decl_pos != path->Decls.second && parent_record_decl; + ++named_decl_pos) + { + //printf ("path[%zu] = %s\n", child_indexes.size(), (*named_decl_pos)->getNameAsCString()); + + child_idx = GetIndexForRecordChild (parent_record_decl, *named_decl_pos, omit_empty_base_classes); + if (child_idx == UINT32_MAX) + { + child_indexes.clear(); + return 0; + } + else + { + child_indexes.push_back (child_idx); + } + } + } + return child_indexes.size(); + } + } + + } + break; + + case Type::ConstantArray: + { +// const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr()); +// const uint64_t element_count = array->getSize().getLimitedValue(); +// +// if (idx < element_count) +// { +// std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(array->getElementType()); +// +// char element_name[32]; +// ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); +// +// child_name.assign(element_name); +// assert(field_type_info.first % 8 == 0); +// child_byte_size = field_type_info.first / 8; +// child_byte_offset = idx * child_byte_size; +// return array->getElementType().getAsOpaquePtr(); +// } + } + break; + +// case Type::MemberPointerType: +// { +// MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr()); +// QualType pointee_type = mem_ptr_type->getPointeeType(); +// +// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) +// { +// return GetIndexOfChildWithName (ast_context, +// mem_ptr_type->getPointeeType().getAsOpaquePtr(), +// name); +// } +// } +// break; +// + case Type::LValueReference: + case Type::RValueReference: + { + ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr()); + QualType pointee_type = reference_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildMemberWithName (ast_context, + reference_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes, + child_indexes); + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildMemberWithName (ast_context, + pointer_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes, + child_indexes); + } + else + { +// if (parent_name) +// { +// child_name.assign(1, '*'); +// child_name += parent_name; +// } +// +// // We have a pointer to an simple type +// if (idx == 0) +// { +// std::pair<uint64_t, unsigned> clang_type_info = ast_context->getTypeInfo(pointee_type); +// assert(clang_type_info.first % 8 == 0); +// child_byte_size = clang_type_info.first / 8; +// child_byte_offset = 0; +// return pointee_type.getAsOpaquePtr(); +// } + } + } + break; + + case Type::Typedef: + return GetIndexOfChildMemberWithName (ast_context, + cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), + name, + omit_empty_base_classes, + child_indexes); + + default: + break; + } + } + return 0; +} + + +// Get the index of the child of "clang_type" whose name matches. This function +// doesn't descend into the children, but only looks one level deep and name +// matches can include base class names. + +uint32_t +ClangASTContext::GetIndexOfChildWithName +( + ASTContext *ast_context, + void *clang_type, + const char *name, + bool omit_empty_base_classes +) +{ + if (clang_type && name && name[0]) + { + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + + assert(record_decl); + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + + if (cxx_record_decl) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + // Skip empty base classes + CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + if (omit_empty_base_classes && RecordHasFields(base_class_decl) == false) + continue; + + if (base_class->getType().getAsString().compare (name) == 0) + return child_idx; + ++child_idx; + } + } + + // Try and find a field that matches NAME + RecordDecl::field_iterator field, field_end; + StringRef name_sref(name); + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { + if (field->getName().equals (name_sref)) + return child_idx; + } + + } + break; + + case Type::ConstantArray: + { +// const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr()); +// const uint64_t element_count = array->getSize().getLimitedValue(); +// +// if (idx < element_count) +// { +// std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(array->getElementType()); +// +// char element_name[32]; +// ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); +// +// child_name.assign(element_name); +// assert(field_type_info.first % 8 == 0); +// child_byte_size = field_type_info.first / 8; +// child_byte_offset = idx * child_byte_size; +// return array->getElementType().getAsOpaquePtr(); +// } + } + break; + +// case Type::MemberPointerType: +// { +// MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr()); +// QualType pointee_type = mem_ptr_type->getPointeeType(); +// +// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) +// { +// return GetIndexOfChildWithName (ast_context, +// mem_ptr_type->getPointeeType().getAsOpaquePtr(), +// name); +// } +// } +// break; +// + case Type::LValueReference: + case Type::RValueReference: + { + ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr()); + QualType pointee_type = reference_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildWithName (ast_context, + reference_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes); + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildWithName (ast_context, + pointer_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes); + } + else + { +// if (parent_name) +// { +// child_name.assign(1, '*'); +// child_name += parent_name; +// } +// +// // We have a pointer to an simple type +// if (idx == 0) +// { +// std::pair<uint64_t, unsigned> clang_type_info = ast_context->getTypeInfo(pointee_type); +// assert(clang_type_info.first % 8 == 0); +// child_byte_size = clang_type_info.first / 8; +// child_byte_offset = 0; +// return pointee_type.getAsOpaquePtr(); +// } + } + } + break; + + case Type::Typedef: + return GetIndexOfChildWithName (ast_context, + cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), + name, + omit_empty_base_classes); + + default: + break; + } + } + return UINT32_MAX; +} + +#pragma mark TagType + +bool +ClangASTContext::SetTagTypeKind (void *tag_clang_type, int kind) +{ + if (tag_clang_type) + { + QualType tag_qual_type(QualType::getFromOpaquePtr(tag_clang_type)); + Type *clang_type = tag_qual_type.getTypePtr(); + if (clang_type) + { + TagType *tag_type = dyn_cast<TagType>(clang_type); + if (tag_type) + { + TagDecl *tag_decl = dyn_cast<TagDecl>(tag_type->getDecl()); + if (tag_decl) + { + tag_decl->setTagKind ((TagDecl::TagKind)kind); + return true; + } + } + } + } + return false; +} + + +#pragma mark DeclContext Functions + +DeclContext * +ClangASTContext::GetDeclContextForType (void *clang_type) +{ + if (clang_type == NULL) + return NULL; + + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::FunctionNoProto: break; + case Type::FunctionProto: break; + case Type::IncompleteArray: break; + case Type::VariableArray: break; + case Type::ConstantArray: break; + case Type::ExtVector: break; + case Type::Vector: break; + case Type::Builtin: break; + case Type::ObjCObjectPointer: break; + case Type::BlockPointer: break; + case Type::Pointer: break; + case Type::LValueReference: break; + case Type::RValueReference: break; + case Type::MemberPointer: break; + case Type::Complex: break; + case Type::ObjCInterface: break; + case Type::Record: + return cast<RecordType>(qual_type)->getDecl(); + case Type::Enum: + return cast<EnumType>(qual_type)->getDecl(); + case Type::Typedef: + return ClangASTContext::GetDeclContextForType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr()); + + case Type::TypeOfExpr: break; + case Type::TypeOf: break; + case Type::Decltype: break; + //case Type::QualifiedName: break; + case Type::TemplateSpecialization: break; + } + // No DeclContext in this type... + return NULL; +} + +#pragma mark Namespace Declarations + +NamespaceDecl * +ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, const Declaration &decl, DeclContext *decl_ctx) +{ + // TODO: Do something intelligent with the Declaration object passed in + // like maybe filling in the SourceLocation with it... + if (name) + { + ASTContext *ast_context = getASTContext(); + if (decl_ctx == NULL) + decl_ctx = ast_context->getTranslationUnitDecl(); + return NamespaceDecl::Create(*ast_context, decl_ctx, SourceLocation(), &ast_context->Idents.get(name)); + } + return NULL; +} + + +#pragma mark Function Types + +FunctionDecl * +ClangASTContext::CreateFunctionDeclaration (const char *name, void *function_clang_type, int storage, bool is_inline) +{ + if (name) + { + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + + if (name && name[0]) + { + return FunctionDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + DeclarationName (&ast_context->Idents.get(name)), + QualType::getFromOpaquePtr(function_clang_type), + NULL, + (FunctionDecl::StorageClass)storage, + (FunctionDecl::StorageClass)storage, + is_inline); + } + else + { + return FunctionDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + DeclarationName (), + QualType::getFromOpaquePtr(function_clang_type), + NULL, + (FunctionDecl::StorageClass)storage, + (FunctionDecl::StorageClass)storage, + is_inline); + } + } + return NULL; +} + +void * +ClangASTContext::CreateFunctionType (void *result_type, void **args, unsigned num_args, bool isVariadic, unsigned TypeQuals) +{ + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + std::vector<QualType> qual_type_args; + for (unsigned i=0; i<num_args; ++i) + qual_type_args.push_back (QualType::getFromOpaquePtr(args[i])); + + // TODO: Detect calling convention in DWARF? + return ast_context->getFunctionType(QualType::getFromOpaquePtr(result_type), + qual_type_args.data(), + qual_type_args.size(), + isVariadic, + TypeQuals, + false, // hasExceptionSpec + false, // hasAnyExceptionSpec, + 0, // NumExs + 0, // const QualType *ExArray + FunctionType::ExtInfo ()).getAsOpaquePtr(); // NoReturn); +} + +ParmVarDecl * +ClangASTContext::CreateParmeterDeclaration (const char *name, void * return_type, int storage) +{ + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + return ParmVarDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + name && name[0] ? &ast_context->Idents.get(name) : NULL, + QualType::getFromOpaquePtr(return_type), + NULL, + (VarDecl::StorageClass)storage, + (VarDecl::StorageClass)storage, + 0); +} + +void +ClangASTContext::SetFunctionParameters (FunctionDecl *function_decl, ParmVarDecl **params, unsigned num_params) +{ + if (function_decl) + function_decl->setParams (params, num_params); +} + + +#pragma mark Array Types + +void * +ClangASTContext::CreateArrayType (void *element_type, size_t element_count, uint32_t bit_stride) +{ + if (element_type) + { + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + llvm::APInt ap_element_count (64, element_count); + return ast_context->getConstantArrayType(QualType::getFromOpaquePtr(element_type), + ap_element_count, + ArrayType::Normal, + 0).getAsOpaquePtr(); // ElemQuals + } + return NULL; +} + + +#pragma mark TagDecl + +bool +ClangASTContext::StartTagDeclarationDefinition (void *clang_type) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + Type *t = qual_type.getTypePtr(); + if (t) + { + TagType *tag_type = dyn_cast<TagType>(t); + if (tag_type) + { + TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + { + tag_decl->startDefinition(); + return true; + } + } + } + } + return false; +} + +bool +ClangASTContext::CompleteTagDeclarationDefinition (void *clang_type) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + Type *t = qual_type.getTypePtr(); + if (t) + { + TagType *tag_type = dyn_cast<TagType>(t); + if (tag_type) + { + TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + { + tag_decl->completeDefinition(); + return true; + } + } + } + } + return false; +} + + +#pragma mark Enumeration Types + +void * +ClangASTContext::CreateEnumerationType (const Declaration &decl, const char *name) +{ + // TODO: Do something intelligent with the Declaration object passed in + // like maybe filling in the SourceLocation with it... + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + EnumDecl *enum_decl = EnumDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + name && name[0] ? &ast_context->Idents.get(name) : NULL, + SourceLocation(), + NULL); + if (enum_decl) + return ast_context->getTagDeclType(enum_decl).getAsOpaquePtr(); + return NULL; +} + +bool +ClangASTContext::AddEnumerationValueToEnumerationType +( + void *enum_clang_type, + void *enumerator_clang_type, + const Declaration &decl, + const char *name, + int64_t enum_value, + uint32_t enum_value_bit_size +) +{ + if (enum_clang_type && enumerator_clang_type && name) + { + // TODO: Do something intelligent with the Declaration object passed in + // like maybe filling in the SourceLocation with it... + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + + assert (ast_context != NULL); + assert (identifier_table != NULL); + QualType enum_qual_type (QualType::getFromOpaquePtr(enum_clang_type)); + + Type *clang_type = enum_qual_type.getTypePtr(); + if (clang_type) + { + const EnumType *enum_type = dyn_cast<EnumType>(clang_type); + + if (enum_type) + { + llvm::APSInt enum_llvm_apsint(enum_value_bit_size, false); + enum_llvm_apsint = enum_value; + EnumConstantDecl *enumerator_decl = + EnumConstantDecl::Create(*ast_context, + enum_type->getDecl(), + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + QualType::getFromOpaquePtr(enumerator_clang_type), + NULL, + enum_llvm_apsint); + + if (enumerator_decl) + { + enum_type->getDecl()->addDecl(enumerator_decl); + return true; + } + } + } + } + return false; +} + +#pragma mark Pointers & References + +void * +ClangASTContext::CreatePointerType (void *clang_type) +{ + if (clang_type) + return getASTContext()->getPointerType(QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return NULL; +} + +void * +ClangASTContext::CreateLValueReferenceType (void *clang_type) +{ + if (clang_type) + return getASTContext()->getLValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return NULL; +} + +void * +ClangASTContext::CreateRValueReferenceType (void *clang_type) +{ + if (clang_type) + return getASTContext()->getRValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return NULL; +} + +size_t +ClangASTContext::GetPointerBitSize () +{ + ASTContext *ast_context = getASTContext(); + return ast_context->getTypeSize(ast_context->VoidPtrTy); +} + +bool +ClangASTContext::IsPointerOrReferenceType (void *clang_type, void **target_type) +{ + if (clang_type == NULL) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::ObjCObjectPointer: + if (target_type) + *target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::BlockPointer: + if (target_type) + *target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::Pointer: + if (target_type) + *target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::MemberPointer: + if (target_type) + *target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::LValueReference: + if (target_type) + *target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr(); + return true; + case Type::RValueReference: + if (target_type) + *target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr(); + return true; + case Type::Typedef: + return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr()); + default: + break; + } + return false; +} + +size_t +ClangASTContext::GetTypeBitSize (clang::ASTContext *ast_context, void *clang_type) +{ + if (clang_type) + return ast_context->getTypeSize(QualType::getFromOpaquePtr(clang_type)); + return 0; +} + +size_t +ClangASTContext::GetTypeBitAlign (clang::ASTContext *ast_context, void *clang_type) +{ + if (clang_type) + return ast_context->getTypeAlign(QualType::getFromOpaquePtr(clang_type)); + return 0; +} + +bool +ClangASTContext::IsIntegerType (void * clang_type, bool &is_signed) +{ + if (!clang_type) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + const BuiltinType *builtin_type = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal()); + + if (builtin_type) + { + if (builtin_type->isInteger()) + is_signed = builtin_type->isSignedInteger(); + + return true; + } + + return false; +} + +bool +ClangASTContext::IsPointerType (void *clang_type, void **target_type) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::ObjCObjectPointer: + if (target_type) + *target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::BlockPointer: + if (target_type) + *target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::Pointer: + if (target_type) + *target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::MemberPointer: + if (target_type) + *target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::Typedef: + return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), target_type); + default: + break; + } + } + return false; +} + +bool +ClangASTContext::IsFloatingPointType (void *clang_type, uint32_t &count, bool &is_complex) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + + if (const BuiltinType *BT = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal())) + { + clang::BuiltinType::Kind kind = BT->getKind(); + if (kind >= BuiltinType::Float && kind <= BuiltinType::LongDouble) + { + count = 1; + is_complex = false; + return true; + } + } + else if (const ComplexType *CT = dyn_cast<ComplexType>(qual_type->getCanonicalTypeInternal())) + { + if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count, is_complex)) + { + count = 2; + is_complex = true; + return true; + } + } + else if (const VectorType *VT = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal())) + { + if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count, is_complex)) + { + count = VT->getNumElements(); + is_complex = false; + return true; + } + } + } + return false; +} + + +bool +ClangASTContext::IsCStringType (void *clang_type, uint32_t &length) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::ConstantArray: + { + ConstantArrayType *array = cast<ConstantArrayType>(qual_type.getTypePtr()); + QualType element_qual_type = array->getElementType(); + Type *canonical_type = element_qual_type->getCanonicalTypeInternal().getTypePtr(); + if (canonical_type && canonical_type->isCharType()) + { + // We know the size of the array and it could be a C string + // since it is an array of characters + length = array->getSize().getLimitedValue(); + return true; + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + Type *pointee_type_ptr = pointer_type->getPointeeType().getTypePtr(); + if (pointee_type_ptr) + { + Type *canonical_type_ptr = pointee_type_ptr->getCanonicalTypeInternal().getTypePtr(); + length = 0; // No length info, read until a NULL terminator is received + if (canonical_type_ptr) + return canonical_type_ptr->isCharType(); + else + return pointee_type_ptr->isCharType(); + } + } + break; + + case Type::Typedef: + return ClangASTContext::IsCStringType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), length); + + case Type::LValueReference: + case Type::RValueReference: + { + ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr()); + Type *pointee_type_ptr = reference_type->getPointeeType().getTypePtr(); + if (pointee_type_ptr) + { + Type *canonical_type_ptr = pointee_type_ptr->getCanonicalTypeInternal().getTypePtr(); + length = 0; // No length info, read until a NULL terminator is received + if (canonical_type_ptr) + return canonical_type_ptr->isCharType(); + else + return pointee_type_ptr->isCharType(); + } + } + break; + } + } + return false; +} + +bool +ClangASTContext::IsArrayType (void * clang_type, void **member_type, uint64_t *size) +{ + if (!clang_type) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + + switch (qual_type->getTypeClass()) + { + case Type::ConstantArray: + if (member_type) + *member_type = cast<ConstantArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = cast<ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULONG_LONG_MAX); + return true; + case Type::IncompleteArray: + if (member_type) + *member_type = cast<IncompleteArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = 0; + return true; + case Type::VariableArray: + if (member_type) + *member_type = cast<VariableArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = 0; + case Type::DependentSizedArray: + if (member_type) + *member_type = cast<DependentSizedArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = 0; + return true; + } + return false; +} + + +#pragma mark Typedefs + +void * +ClangASTContext::CreateTypedefType (const char *name, void *clang_type, DeclContext *decl_ctx) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + assert (ast_context != NULL); + assert (identifier_table != NULL); + if (decl_ctx == NULL) + decl_ctx = ast_context->getTranslationUnitDecl(); + TypedefDecl *decl = TypedefDecl::Create(*ast_context, + decl_ctx, + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + ast_context->CreateTypeSourceInfo(qual_type)); + + // Get a uniqued QualType for the typedef decl type + return ast_context->getTypedefType (decl).getAsOpaquePtr(); + } + return NULL; +} + + +std::string +ClangASTContext::GetTypeName (void *opaque_qual_type) +{ + std::string return_name; + + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(opaque_qual_type)); + + const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (typedef_type) + { + const clang::TypedefDecl *typedef_decl = typedef_type->getDecl(); + return_name = typedef_decl->getQualifiedNameAsString(); + } + else + { + return_name = qual_type.getAsString(); + } + + return return_name; +} + +// Disable this for now since I can't seem to get a nicely formatted float +// out of the APFloat class without just getting the float, double or quad +// and then using a formatted print on it which defeats the purpose. We ideally +// would like to get perfect string values for any kind of float semantics +// so we can support remote targets. The code below also requires a patch to +// llvm::APInt. +//bool +//ClangASTContext::ConvertFloatValueToString (ASTContext *ast_context, void *clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str) +//{ +// uint32_t count = 0; +// bool is_complex = false; +// if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex)) +// { +// unsigned num_bytes_per_float = byte_size / count; +// unsigned num_bits_per_float = num_bytes_per_float * 8; +// +// float_str.clear(); +// uint32_t i; +// for (i=0; i<count; i++) +// { +// APInt ap_int(num_bits_per_float, bytes + i * num_bytes_per_float, (APInt::ByteOrder)apint_byte_order); +// bool is_ieee = false; +// APFloat ap_float(ap_int, is_ieee); +// char s[1024]; +// unsigned int hex_digits = 0; +// bool upper_case = false; +// +// if (ap_float.convertToHexString(s, hex_digits, upper_case, APFloat::rmNearestTiesToEven) > 0) +// { +// if (i > 0) +// float_str.append(", "); +// float_str.append(s); +// if (i == 1 && is_complex) +// float_str.append(1, 'i'); +// } +// } +// return !float_str.empty(); +// } +// return false; +//} + +size_t +ClangASTContext::ConvertStringToFloatValue (ASTContext *ast_context, void *clang_type, const char *s, uint8_t *dst, size_t dst_size) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + uint32_t count = 0; + bool is_complex = false; + if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex)) + { + // TODO: handle complex and vector types + if (count != 1) + return false; + + StringRef s_sref(s); + APFloat ap_float(ast_context->getFloatTypeSemantics(qual_type), s_sref); + + const uint64_t bit_size = ast_context->getTypeSize (qual_type); + const uint64_t byte_size = bit_size / 8; + if (dst_size >= byte_size) + { + if (bit_size == sizeof(float)*8) + { + float float32 = ap_float.convertToFloat(); + ::memcpy (dst, &float32, byte_size); + return byte_size; + } + else if (bit_size >= 64) + { + llvm::APInt ap_int(ap_float.bitcastToAPInt()); + ::memcpy (dst, ap_int.getRawData(), byte_size); + return byte_size; + } + } + } + } + return 0; +} |