diff options
Diffstat (limited to 'source/Symbol/ClangASTContext.cpp')
-rw-r--r-- | source/Symbol/ClangASTContext.cpp | 8450 |
1 files changed, 8187 insertions, 263 deletions
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp index 68bcde8a47c1..8b11c239aabf 100644 --- a/source/Symbol/ClangASTContext.cpp +++ b/source/Symbol/ClangASTContext.cpp @@ -13,6 +13,7 @@ // C++ Includes #include <mutex> // std::once #include <string> +#include <vector> // Other libraries and framework includes @@ -39,8 +40,10 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" +#include "clang/AST/VTableBuilder.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" @@ -58,19 +61,33 @@ #include <assert.h> #endif +#include "llvm/Support/Signals.h" + #include "lldb/Core/ArchSpec.h" -#include "lldb/Core/dwarf.h" #include "lldb/Core/Flags.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/RegularExpression.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/ThreadSafeDenseMap.h" #include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Expression/ASTDumper.h" +#include "Plugins/ExpressionParser/Clang/ClangUserExpression.h" +#include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h" +#include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/VerifyDecl.h" #include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Process.h" +#include "lldb/Target/Language.h" #include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" #include <stdio.h> @@ -81,6 +98,17 @@ using namespace lldb_private; using namespace llvm; using namespace clang; +namespace +{ + static inline bool ClangASTContextSupportsLanguage (lldb::LanguageType language) + { + return language == eLanguageTypeUnknown || // Clang is the default type system + Language::LanguageIsC (language) || + Language::LanguageIsCPlusPlus (language) || + Language::LanguageIsObjC (language); + } +} + typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, ClangASTContext*> ClangASTMap; static ClangASTMap & @@ -277,22 +305,23 @@ ParseLangArgs (LangOptions &Opts, InputKind IK, const char* triple) } -ClangASTContext::ClangASTContext (const char *target_triple) : - m_target_triple(), - m_ast_ap(), - m_language_options_ap(), - m_source_manager_ap(), - m_diagnostics_engine_ap(), - m_target_options_rp(), - m_target_info_ap(), - m_identifier_table_ap(), - m_selector_table_ap(), - m_builtins_ap(), +ClangASTContext::ClangASTContext (const char *target_triple) : + TypeSystem (TypeSystem::eKindClang), + m_target_triple (), + m_ast_ap (), + m_language_options_ap (), + m_source_manager_ap (), + m_diagnostics_engine_ap (), + m_target_options_rp (), + m_target_info_ap (), + m_identifier_table_ap (), + m_selector_table_ap (), + m_builtins_ap (), m_callback_tag_decl (nullptr), m_callback_objc_decl (nullptr), m_callback_baton (nullptr), - m_pointer_byte_size (0) - + m_pointer_byte_size (0), + m_ast_owned (false) { if (target_triple && target_triple[0]) SetTargetTriple (target_triple); @@ -306,6 +335,8 @@ ClangASTContext::~ClangASTContext() if (m_ast_ap.get()) { GetASTMap().Erase(m_ast_ap.get()); + if (!m_ast_owned) + m_ast_ap.release(); } m_builtins_ap.reset(); @@ -319,6 +350,127 @@ ClangASTContext::~ClangASTContext() m_ast_ap.reset(); } +ConstString +ClangASTContext::GetPluginNameStatic() +{ + return ConstString("clang"); +} + +ConstString +ClangASTContext::GetPluginName() +{ + return ClangASTContext::GetPluginNameStatic(); +} + +uint32_t +ClangASTContext::GetPluginVersion() +{ + return 1; +} + +lldb::TypeSystemSP +ClangASTContext::CreateInstance (lldb::LanguageType language, + lldb_private::Module *module, + Target *target) +{ + if (ClangASTContextSupportsLanguage(language)) + { + ArchSpec arch; + if (module) + arch = module->GetArchitecture(); + else if (target) + arch = target->GetArchitecture(); + + if (arch.IsValid()) + { + ArchSpec fixed_arch = arch; + // LLVM wants this to be set to iOS or MacOSX; if we're working on + // a bare-boards type image, change the triple for llvm's benefit. + if (fixed_arch.GetTriple().getVendor() == llvm::Triple::Apple && + fixed_arch.GetTriple().getOS() == llvm::Triple::UnknownOS) + { + if (fixed_arch.GetTriple().getArch() == llvm::Triple::arm || + fixed_arch.GetTriple().getArch() == llvm::Triple::aarch64 || + fixed_arch.GetTriple().getArch() == llvm::Triple::thumb) + { + fixed_arch.GetTriple().setOS(llvm::Triple::IOS); + } + else + { + fixed_arch.GetTriple().setOS(llvm::Triple::MacOSX); + } + } + + if (module) + { + std::shared_ptr<ClangASTContext> ast_sp(new ClangASTContext); + if (ast_sp) + { + ast_sp->SetArchitecture (fixed_arch); + } + return ast_sp; + } + else if (target && target->IsValid()) + { + std::shared_ptr<ClangASTContextForExpressions> ast_sp(new ClangASTContextForExpressions(*target)); + if (ast_sp) + { + ast_sp->SetArchitecture(fixed_arch); + ast_sp->m_scratch_ast_source_ap.reset (new ClangASTSource(target->shared_from_this())); + ast_sp->m_scratch_ast_source_ap->InstallASTContext(ast_sp->getASTContext()); + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source(ast_sp->m_scratch_ast_source_ap->CreateProxy()); + ast_sp->SetExternalSource(proxy_ast_source); + return ast_sp; + } + } + } + } + return lldb::TypeSystemSP(); +} + +void +ClangASTContext::EnumerateSupportedLanguages(std::set<lldb::LanguageType> &languages_for_types, std::set<lldb::LanguageType> &languages_for_expressions) +{ + static std::vector<lldb::LanguageType> s_supported_languages_for_types({ + lldb::eLanguageTypeC89, + lldb::eLanguageTypeC, + lldb::eLanguageTypeC11, + lldb::eLanguageTypeC_plus_plus, + lldb::eLanguageTypeC99, + lldb::eLanguageTypeObjC, + lldb::eLanguageTypeObjC_plus_plus, + lldb::eLanguageTypeC_plus_plus_03, + lldb::eLanguageTypeC_plus_plus_11, + lldb::eLanguageTypeC11, + lldb::eLanguageTypeC_plus_plus_14}); + + static std::vector<lldb::LanguageType> s_supported_languages_for_expressions({ + lldb::eLanguageTypeC_plus_plus, + lldb::eLanguageTypeObjC_plus_plus, + lldb::eLanguageTypeC_plus_plus_03, + lldb::eLanguageTypeC_plus_plus_11, + lldb::eLanguageTypeC_plus_plus_14}); + + languages_for_types.insert(s_supported_languages_for_types.begin(), s_supported_languages_for_types.end()); + languages_for_expressions.insert(s_supported_languages_for_expressions.begin(), s_supported_languages_for_expressions.end()); +} + + +void +ClangASTContext::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "clang base AST context plug-in", + CreateInstance, + EnumerateSupportedLanguages); +} + +void +ClangASTContext::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + void ClangASTContext::Clear() @@ -389,13 +541,23 @@ ClangASTContext::RemoveExternalSource () } } - +void +ClangASTContext::setASTContext(clang::ASTContext *ast_ctx) +{ + if (!m_ast_owned) { + m_ast_ap.release(); + } + m_ast_owned = false; + m_ast_ap.reset(ast_ctx); + GetASTMap().Insert(ast_ctx, this); +} ASTContext * ClangASTContext::getASTContext() { if (m_ast_ap.get() == nullptr) { + m_ast_owned = true; m_ast_ap.reset(new ASTContext (*getLanguageOptions(), *getSourceManager(), *getIdentifierTable(), @@ -417,6 +579,13 @@ ClangASTContext::getASTContext() } GetASTMap().Insert(m_ast_ap.get(), this); + + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_ap (new ClangExternalASTSourceCallbacks (ClangASTContext::CompleteTagDecl, + ClangASTContext::CompleteObjCInterfaceDecl, + nullptr, + ClangASTContext::LayoutRecordType, + this)); + SetExternalSource (ast_source_ap); } return m_ast_ap.get(); } @@ -494,6 +663,14 @@ ClangASTContext::getDiagnosticsEngine() return m_diagnostics_engine_ap.get(); } +clang::MangleContext * +ClangASTContext::getMangleContext() +{ + if (m_mangle_ctx_ap.get() == nullptr) + m_mangle_ctx_ap.reset (getASTContext()->createMangleContext()); + return m_mangle_ctx_ap.get(); +} + class NullDiagnosticConsumer : public DiagnosticConsumer { public: @@ -561,72 +738,74 @@ QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast, QualType qual_t return true; return false; } -ClangASTType -ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (Encoding encoding, uint32_t bit_size) + +CompilerType +ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (Encoding encoding, size_t bit_size) { return ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (getASTContext(), encoding, bit_size); } -ClangASTType +CompilerType ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (ASTContext *ast, Encoding encoding, uint32_t bit_size) { if (!ast) - return ClangASTType(); - + return CompilerType(); switch (encoding) { case eEncodingInvalid: if (QualTypeMatchesBitSize (bit_size, ast, ast->VoidPtrTy)) - return ClangASTType (ast, ast->VoidPtrTy.getAsOpaquePtr()); + return CompilerType (ast, ast->VoidPtrTy); break; case eEncodingUint: if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) - return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedCharTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) - return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedShortTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) - return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedIntTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy)) - return ClangASTType (ast, ast->UnsignedLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedLongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy)) - return ClangASTType (ast, ast->UnsignedLongLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedLongLongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty)) - return ClangASTType (ast, ast->UnsignedInt128Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedInt128Ty); break; case eEncodingSint: if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) - return ClangASTType (ast, ast->CharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->CharTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy)) - return ClangASTType (ast, ast->ShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->ShortTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy)) - return ClangASTType (ast, ast->IntTy.getAsOpaquePtr()); + return CompilerType (ast, ast->IntTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->LongTy)) - return ClangASTType (ast, ast->LongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy)) - return ClangASTType (ast, ast->LongLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongLongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty)) - return ClangASTType (ast, ast->Int128Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->Int128Ty); break; case eEncodingIEEE754: if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy)) - return ClangASTType (ast, ast->FloatTy.getAsOpaquePtr()); + return CompilerType (ast, ast->FloatTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy)) - return ClangASTType (ast, ast->DoubleTy.getAsOpaquePtr()); + return CompilerType (ast, ast->DoubleTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy)) - return ClangASTType (ast, ast->LongDoubleTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongDoubleTy); + if (QualTypeMatchesBitSize (bit_size, ast, ast->HalfTy)) + return CompilerType (ast, ast->HalfTy); break; case eEncodingVector: // Sanity check that bit_size is a multiple of 8's. if (bit_size && !(bit_size & 0x7u)) - return ClangASTType (ast, ast->getExtVectorType (ast->UnsignedCharTy, bit_size/8).getAsOpaquePtr()); + return CompilerType (ast, ast->getExtVectorType (ast->UnsignedCharTy, bit_size/8)); break; } - return ClangASTType(); + return CompilerType(); } @@ -694,7 +873,7 @@ ClangASTContext::GetBasicTypeEnumeration (const ConstString &name) return eBasicTypeInvalid; } -ClangASTType +CompilerType ClangASTContext::GetBasicType (ASTContext *ast, const ConstString &name) { if (ast) @@ -702,7 +881,7 @@ ClangASTContext::GetBasicType (ASTContext *ast, const ConstString &name) lldb::BasicType basic_type = ClangASTContext::GetBasicTypeEnumeration (name); return ClangASTContext::GetBasicType (ast, basic_type); } - return ClangASTType(); + return CompilerType(); } uint32_t @@ -713,18 +892,18 @@ ClangASTContext::GetPointerByteSize () return m_pointer_byte_size; } -ClangASTType +CompilerType ClangASTContext::GetBasicType (lldb::BasicType basic_type) { return GetBasicType (getASTContext(), basic_type); } -ClangASTType +CompilerType ClangASTContext::GetBasicType (ASTContext *ast, lldb::BasicType basic_type) { if (ast) { - clang_type_t clang_type = nullptr; + lldb::opaque_compiler_type_t clang_type = nullptr; switch (basic_type) { @@ -827,13 +1006,13 @@ ClangASTContext::GetBasicType (ASTContext *ast, lldb::BasicType basic_type) } if (clang_type) - return ClangASTType (ast, clang_type); + return CompilerType (GetASTContext(ast), clang_type); } - return ClangASTType(); + return CompilerType(); } -ClangASTType +CompilerType ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name, uint32_t dw_ate, uint32_t bit_size) { ASTContext *ast = getASTContext(); @@ -849,18 +1028,18 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name case DW_ATE_address: if (QualTypeMatchesBitSize (bit_size, ast, ast->VoidPtrTy)) - return ClangASTType (ast, ast->VoidPtrTy.getAsOpaquePtr()); + return CompilerType (ast, ast->VoidPtrTy); break; case DW_ATE_boolean: if (QualTypeMatchesBitSize (bit_size, ast, ast->BoolTy)) - return ClangASTType (ast, ast->BoolTy.getAsOpaquePtr()); + return CompilerType (ast, ast->BoolTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) - return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedCharTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) - return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedShortTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) - return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedIntTy); break; case DW_ATE_lo_user: @@ -869,40 +1048,42 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name { if (::strstr(type_name, "complex")) { - ClangASTType complex_int_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("int", DW_ATE_signed, bit_size/2); - return ClangASTType (ast, ast->getComplexType (complex_int_clang_type.GetQualType()).getAsOpaquePtr()); + CompilerType complex_int_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("int", DW_ATE_signed, bit_size/2); + return CompilerType (ast, ast->getComplexType (GetQualType(complex_int_clang_type))); } } break; case DW_ATE_complex_float: if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatComplexTy)) - return ClangASTType (ast, ast->FloatComplexTy.getAsOpaquePtr()); + return CompilerType (ast, ast->FloatComplexTy); else if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleComplexTy)) - return ClangASTType (ast, ast->DoubleComplexTy.getAsOpaquePtr()); + return CompilerType (ast, ast->DoubleComplexTy); else if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleComplexTy)) - return ClangASTType (ast, ast->LongDoubleComplexTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongDoubleComplexTy); else { - ClangASTType complex_float_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("float", DW_ATE_float, bit_size/2); - return ClangASTType (ast, ast->getComplexType (complex_float_clang_type.GetQualType()).getAsOpaquePtr()); + CompilerType complex_float_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("float", DW_ATE_float, bit_size/2); + return CompilerType (ast, ast->getComplexType (GetQualType(complex_float_clang_type))); } break; case DW_ATE_float: if (streq(type_name, "float") && QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy)) - return ClangASTType (ast, ast->FloatTy.getAsOpaquePtr()); + return CompilerType (ast, ast->FloatTy); if (streq(type_name, "double") && QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy)) - return ClangASTType (ast, ast->DoubleTy.getAsOpaquePtr()); + return CompilerType (ast, ast->DoubleTy); if (streq(type_name, "long double") && QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy)) - return ClangASTType (ast, ast->LongDoubleTy.getAsOpaquePtr()); - // Fall back to not requring a name match + return CompilerType (ast, ast->LongDoubleTy); + // Fall back to not requiring a name match if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy)) - return ClangASTType (ast, ast->FloatTy.getAsOpaquePtr()); + return CompilerType (ast, ast->FloatTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy)) - return ClangASTType (ast, ast->DoubleTy.getAsOpaquePtr()); + return CompilerType (ast, ast->DoubleTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy)) - return ClangASTType (ast, ast->LongDoubleTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongDoubleTy); + if (QualTypeMatchesBitSize (bit_size, ast, ast->HalfTy)) + return CompilerType (ast, ast->HalfTy); break; case DW_ATE_signed: @@ -911,57 +1092,57 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name if (streq(type_name, "wchar_t") && QualTypeMatchesBitSize (bit_size, ast, ast->WCharTy) && (getTargetInfo() && TargetInfo::isTypeSigned (getTargetInfo()->getWCharType()))) - return ClangASTType (ast, ast->WCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->WCharTy); if (streq(type_name, "void") && QualTypeMatchesBitSize (bit_size, ast, ast->VoidTy)) - return ClangASTType (ast, ast->VoidTy.getAsOpaquePtr()); + return CompilerType (ast, ast->VoidTy); if (strstr(type_name, "long long") && QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy)) - return ClangASTType (ast, ast->LongLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongLongTy); if (strstr(type_name, "long") && QualTypeMatchesBitSize (bit_size, ast, ast->LongTy)) - return ClangASTType (ast, ast->LongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongTy); if (strstr(type_name, "short") && QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy)) - return ClangASTType (ast, ast->ShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->ShortTy); if (strstr(type_name, "char")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) - return ClangASTType (ast, ast->CharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->CharTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy)) - return ClangASTType (ast, ast->SignedCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->SignedCharTy); } if (strstr(type_name, "int")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy)) - return ClangASTType (ast, ast->IntTy.getAsOpaquePtr()); + return CompilerType (ast, ast->IntTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty)) - return ClangASTType (ast, ast->Int128Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->Int128Ty); } } // We weren't able to match up a type name, just search by size if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) - return ClangASTType (ast, ast->CharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->CharTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy)) - return ClangASTType (ast, ast->ShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->ShortTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy)) - return ClangASTType (ast, ast->IntTy.getAsOpaquePtr()); + return CompilerType (ast, ast->IntTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->LongTy)) - return ClangASTType (ast, ast->LongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy)) - return ClangASTType (ast, ast->LongLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->LongLongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty)) - return ClangASTType (ast, ast->Int128Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->Int128Ty); break; case DW_ATE_signed_char: if (ast->getLangOpts().CharIsSigned && type_name && streq(type_name, "char")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) - return ClangASTType (ast, ast->CharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->CharTy); } if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy)) - return ClangASTType (ast, ast->SignedCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->SignedCharTy); break; case DW_ATE_unsigned: @@ -972,62 +1153,62 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name if (QualTypeMatchesBitSize (bit_size, ast, ast->WCharTy)) { if (!(getTargetInfo() && TargetInfo::isTypeSigned (getTargetInfo()->getWCharType()))) - return ClangASTType (ast, ast->WCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->WCharTy); } } if (strstr(type_name, "long long")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy)) - return ClangASTType (ast, ast->UnsignedLongLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedLongLongTy); } else if (strstr(type_name, "long")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy)) - return ClangASTType (ast, ast->UnsignedLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedLongTy); } else if (strstr(type_name, "short")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) - return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedShortTy); } else if (strstr(type_name, "char")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) - return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedCharTy); } else if (strstr(type_name, "int")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) - return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedIntTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty)) - return ClangASTType (ast, ast->UnsignedInt128Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedInt128Ty); } } // We weren't able to match up a type name, just search by size if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) - return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedCharTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) - return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedShortTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) - return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedIntTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy)) - return ClangASTType (ast, ast->UnsignedLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedLongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy)) - return ClangASTType (ast, ast->UnsignedLongLongTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedLongLongTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty)) - return ClangASTType (ast, ast->UnsignedInt128Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedInt128Ty); break; case DW_ATE_unsigned_char: if (!ast->getLangOpts().CharIsSigned && type_name && streq(type_name, "char")) { if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) - return ClangASTType (ast, ast->CharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->CharTy); } if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) - return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedCharTy); if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) - return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr()); + return CompilerType (ast, ast->UnsignedShortTy); break; case DW_ATE_imaginary_float: @@ -1038,11 +1219,11 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name { if (streq(type_name, "char16_t")) { - return ClangASTType (ast, ast->Char16Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->Char16Ty); } else if (streq(type_name, "char32_t")) { - return ClangASTType (ast, ast->Char32Ty.getAsOpaquePtr()); + return CompilerType (ast, ast->Char32Ty); } } break; @@ -1058,18 +1239,18 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name { Host::SystemLog (Host::eSystemLogError, "error: need to add support for DW_TAG_base_type encoded with DW_ATE = 0x%x, bit_size = %u\n", dw_ate, bit_size); } - return ClangASTType (); + return CompilerType (); } -ClangASTType +CompilerType ClangASTContext::GetUnknownAnyType(clang::ASTContext *ast) { if (ast) - return ClangASTType (ast, ast->UnknownAnyTy.getAsOpaquePtr()); - return ClangASTType(); + return CompilerType (ast, ast->UnknownAnyTy); + return CompilerType(); } -ClangASTType +CompilerType ClangASTContext::GetCStringType (bool is_const) { ASTContext *ast = getASTContext(); @@ -1078,7 +1259,7 @@ ClangASTContext::GetCStringType (bool is_const) if (is_const) char_type.addConst(); - return ClangASTType (ast, ast->getPointerType(char_type).getAsOpaquePtr()); + return CompilerType (ast, ast->getPointerType(char_type)); } clang::DeclContext * @@ -1087,23 +1268,6 @@ ClangASTContext::GetTranslationUnitDecl (clang::ASTContext *ast) return ast->getTranslationUnitDecl(); } -ClangASTType -ClangASTContext::CopyType (ASTContext *dst_ast, - ClangASTType src) -{ - FileSystemOptions file_system_options; - ASTContext *src_ast = src.GetASTContext(); - FileManager file_manager (file_system_options); - ASTImporter importer(*dst_ast, file_manager, - *src_ast, file_manager, - false); - - QualType dst (importer.Import(src.GetQualType())); - - return ClangASTType (dst_ast, dst.getAsOpaquePtr()); -} - - clang::Decl * ClangASTContext::CopyDecl (ASTContext *dst_ast, ASTContext *src_ast, @@ -1119,19 +1283,19 @@ ClangASTContext::CopyDecl (ASTContext *dst_ast, } bool -ClangASTContext::AreTypesSame (ClangASTType type1, - ClangASTType type2, +ClangASTContext::AreTypesSame (CompilerType type1, + CompilerType type2, bool ignore_qualifiers) { - ASTContext *ast = type1.GetASTContext(); - if (ast != type2.GetASTContext()) + ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(type1.GetTypeSystem()); + if (!ast || ast != type2.GetTypeSystem()) return false; if (type1.GetOpaqueQualType() == type2.GetOpaqueQualType()) return true; - QualType type1_qual = type1.GetQualType(); - QualType type2_qual = type2.GetQualType(); + QualType type1_qual = GetQualType(type1); + QualType type2_qual = GetQualType(type2); if (ignore_qualifiers) { @@ -1139,21 +1303,21 @@ ClangASTContext::AreTypesSame (ClangASTType type1, type2_qual = type2_qual.getUnqualifiedType(); } - return ast->hasSameType (type1_qual, type2_qual); + return ast->getASTContext()->hasSameType (type1_qual, type2_qual); } -ClangASTType +CompilerType ClangASTContext::GetTypeForDecl (clang::NamedDecl *decl) { if (clang::ObjCInterfaceDecl *interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) return GetTypeForDecl(interface_decl); if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl)) return GetTypeForDecl(tag_decl); - return ClangASTType(); + return CompilerType(); } -ClangASTType +CompilerType ClangASTContext::GetTypeForDecl (TagDecl *decl) { // No need to call the getASTContext() accessor (which can create the AST @@ -1161,11 +1325,11 @@ ClangASTContext::GetTypeForDecl (TagDecl *decl) // AST if our AST didn't already exist... ASTContext *ast = &decl->getASTContext(); if (ast) - return ClangASTType (ast, ast->getTagDeclType(decl).getAsOpaquePtr()); - return ClangASTType(); + return CompilerType (ast, ast->getTagDeclType(decl)); + return CompilerType(); } -ClangASTType +CompilerType ClangASTContext::GetTypeForDecl (ObjCInterfaceDecl *decl) { // No need to call the getASTContext() accessor (which can create the AST @@ -1173,13 +1337,13 @@ ClangASTContext::GetTypeForDecl (ObjCInterfaceDecl *decl) // AST if our AST didn't already exist... ASTContext *ast = &decl->getASTContext(); if (ast) - return ClangASTType (ast, ast->getObjCInterfaceType(decl).getAsOpaquePtr()); - return ClangASTType(); + return CompilerType (ast, ast->getObjCInterfaceType(decl)); + return CompilerType(); } #pragma mark Structure, Unions, Classes -ClangASTType +CompilerType ClangASTContext::CreateRecordType (DeclContext *decl_ctx, AccessType access_type, const char *name, @@ -1230,9 +1394,9 @@ ClangASTContext::CreateRecordType (DeclContext *decl_ctx, if (decl_ctx) decl_ctx->addDecl (decl); - return ClangASTType(ast, ast->getTagDeclType(decl).getAsOpaquePtr()); + return CompilerType(ast, ast->getTagDeclType(decl)); } - return ClangASTType(); + return CompilerType(); } static TemplateParameterList * @@ -1282,8 +1446,7 @@ CreateTemplateParameterList (ASTContext *ast, TemplateParameterList *template_param_list = TemplateParameterList::Create (*ast, SourceLocation(), SourceLocation(), - &template_param_decls.front(), - template_param_decls.size(), + template_param_decls, SourceLocation()); return template_param_list; } @@ -1434,16 +1597,16 @@ ClangASTContext::CreateClassTemplateSpecializationDecl (DeclContext *decl_ctx, return class_template_specialization_decl; } -ClangASTType +CompilerType ClangASTContext::CreateClassTemplateSpecializationType (ClassTemplateSpecializationDecl *class_template_specialization_decl) { if (class_template_specialization_decl) { ASTContext *ast = getASTContext(); if (ast) - return ClangASTType(ast, ast->getTagDeclType(class_template_specialization_decl).getAsOpaquePtr()); + return CompilerType(ast, ast->getTagDeclType(class_template_specialization_decl)); } - return ClangASTType(); + return CompilerType(); } static inline bool @@ -1571,7 +1734,7 @@ ClangASTContext::RecordHasFields (const RecordDecl *record_decl) #pragma mark Objective C Classes -ClangASTType +CompilerType ClangASTContext::CreateObjCClass ( const char *name, @@ -1600,7 +1763,7 @@ ClangASTContext::CreateObjCClass if (decl && metadata) SetMetadata(ast, decl, *metadata); - return ClangASTType (ast, ast->getObjCInterfaceType(decl)); + return CompilerType (ast, ast->getObjCInterfaceType(decl)); } static inline bool @@ -1714,24 +1877,6 @@ ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, DeclContext *d // BAD!!! } } - - - if (namespace_decl) - { - // If we make it here, we are creating the anonymous namespace decl - // for the first time, so we need to do the using directive magic - // like SEMA does - UsingDirectiveDecl* using_directive_decl = UsingDirectiveDecl::Create (*ast, - decl_ctx, - SourceLocation(), - SourceLocation(), - NestedNameSpecifierLoc(), - SourceLocation(), - namespace_decl, - decl_ctx); - using_directive_decl->setImplicit(); - decl_ctx->addDecl(using_directive_decl); - } } #ifdef LLDB_CONFIGURATION_DEBUG VerifyDecl(namespace_decl); @@ -1740,12 +1885,104 @@ ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, DeclContext *d } +clang::BlockDecl * +ClangASTContext::CreateBlockDeclaration (clang::DeclContext *ctx) +{ + if (ctx != nullptr) + { + clang::BlockDecl *decl = clang::BlockDecl::Create(*getASTContext(), ctx, clang::SourceLocation()); + ctx->addDecl(decl); + return decl; + } + return nullptr; +} + +clang::DeclContext * +FindLCABetweenDecls(clang::DeclContext *left, clang::DeclContext *right, clang::DeclContext *root) +{ + if (root == nullptr) + return nullptr; + + std::set<clang::DeclContext *> path_left; + for (clang::DeclContext *d = left; d != nullptr; d = d->getParent()) + path_left.insert(d); + + for (clang::DeclContext *d = right; d != nullptr; d = d->getParent()) + if (path_left.find(d) != path_left.end()) + return d; + + return nullptr; +} + +clang::UsingDirectiveDecl * +ClangASTContext::CreateUsingDirectiveDeclaration (clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) +{ + if (decl_ctx != nullptr && ns_decl != nullptr) + { + clang::TranslationUnitDecl *translation_unit = (clang::TranslationUnitDecl *)GetTranslationUnitDecl(getASTContext()); + clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create(*getASTContext(), + decl_ctx, + clang::SourceLocation(), + clang::SourceLocation(), + clang::NestedNameSpecifierLoc(), + clang::SourceLocation(), + ns_decl, + FindLCABetweenDecls(decl_ctx, ns_decl, translation_unit)); + decl_ctx->addDecl(using_decl); + return using_decl; + } + return nullptr; +} + +clang::UsingDecl * +ClangASTContext::CreateUsingDeclaration (clang::DeclContext *current_decl_ctx, clang::NamedDecl *target) +{ + if (current_decl_ctx != nullptr && target != nullptr) + { + clang::UsingDecl *using_decl = clang::UsingDecl::Create(*getASTContext(), + current_decl_ctx, + clang::SourceLocation(), + clang::NestedNameSpecifierLoc(), + clang::DeclarationNameInfo(), + false); + clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create(*getASTContext(), + current_decl_ctx, + clang::SourceLocation(), + using_decl, + target); + using_decl->addShadowDecl(shadow_decl); + current_decl_ctx->addDecl(using_decl); + return using_decl; + } + return nullptr; +} + +clang::VarDecl * +ClangASTContext::CreateVariableDeclaration (clang::DeclContext *decl_context, const char *name, clang::QualType type) +{ + if (decl_context != nullptr) + { + clang::VarDecl *var_decl = clang::VarDecl::Create(*getASTContext(), + decl_context, + clang::SourceLocation(), + clang::SourceLocation(), + name && name[0] ? &getASTContext()->Idents.getOwn(name) : nullptr, + type, + nullptr, + clang::SC_None); + var_decl->setAccess(clang::AS_public); + decl_context->addDecl(var_decl); + return var_decl; + } + return nullptr; +} + #pragma mark Function Types FunctionDecl * ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx, const char *name, - const ClangASTType &function_clang_type, + const CompilerType &function_clang_type, int storage, bool is_inline) { @@ -1765,7 +2002,7 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx, SourceLocation(), SourceLocation(), DeclarationName (&ast->Idents.get(name)), - function_clang_type.GetQualType(), + GetQualType(function_clang_type), nullptr, (clang::StorageClass)storage, is_inline, @@ -1779,7 +2016,7 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx, SourceLocation(), SourceLocation(), DeclarationName (), - function_clang_type.GetQualType(), + GetQualType(function_clang_type), nullptr, (clang::StorageClass)storage, is_inline, @@ -1796,10 +2033,10 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx, return func_decl; } -ClangASTType +CompilerType ClangASTContext::CreateFunctionType (ASTContext *ast, - const ClangASTType& result_type, - const ClangASTType *args, + const CompilerType& result_type, + const CompilerType *args, unsigned num_args, bool is_variadic, unsigned type_quals) @@ -1807,7 +2044,7 @@ ClangASTContext::CreateFunctionType (ASTContext *ast, assert (ast != nullptr); std::vector<QualType> qual_type_args; for (unsigned i=0; i<num_args; ++i) - qual_type_args.push_back (args[i].GetQualType()); + qual_type_args.push_back (GetQualType(args[i])); // TODO: Detect calling convention in DWARF? FunctionProtoType::ExtProtoInfo proto_info; @@ -1816,13 +2053,13 @@ ClangASTContext::CreateFunctionType (ASTContext *ast, proto_info.TypeQuals = type_quals; proto_info.RefQualifier = RQ_None; - return ClangASTType (ast, ast->getFunctionType (result_type.GetQualType(), + return CompilerType (ast, ast->getFunctionType (GetQualType(result_type), qual_type_args, - proto_info).getAsOpaquePtr()); + proto_info)); } ParmVarDecl * -ClangASTContext::CreateParameterDeclaration (const char *name, const ClangASTType ¶m_type, int storage) +ClangASTContext::CreateParameterDeclaration (const char *name, const CompilerType ¶m_type, int storage) { ASTContext *ast = getASTContext(); assert (ast != nullptr); @@ -1831,7 +2068,7 @@ ClangASTContext::CreateParameterDeclaration (const char *name, const ClangASTTyp SourceLocation(), SourceLocation(), name && name[0] ? &ast->Idents.get(name) : nullptr, - param_type.GetQualType(), + GetQualType(param_type), nullptr, (clang::StorageClass)storage, nullptr); @@ -1847,8 +2084,8 @@ ClangASTContext::SetFunctionParameters (FunctionDecl *function_decl, ParmVarDecl #pragma mark Array Types -ClangASTType -ClangASTContext::CreateArrayType (const ClangASTType &element_type, +CompilerType +ClangASTContext::CreateArrayType (const CompilerType &element_type, size_t element_count, bool is_vector) { @@ -1859,7 +2096,7 @@ ClangASTContext::CreateArrayType (const ClangASTType &element_type, if (is_vector) { - return ClangASTType (ast, ast->getExtVectorType(element_type.GetQualType(), element_count).getAsOpaquePtr()); + return CompilerType (ast, ast->getExtVectorType(GetQualType(element_type), element_count)); } else { @@ -1867,59 +2104,59 @@ ClangASTContext::CreateArrayType (const ClangASTType &element_type, llvm::APInt ap_element_count (64, element_count); if (element_count == 0) { - return ClangASTType (ast, ast->getIncompleteArrayType (element_type.GetQualType(), + return CompilerType (ast, ast->getIncompleteArrayType (GetQualType(element_type), ArrayType::Normal, - 0).getAsOpaquePtr()); + 0)); } else { - return ClangASTType (ast, ast->getConstantArrayType (element_type.GetQualType(), + return CompilerType (ast, ast->getConstantArrayType (GetQualType(element_type), ap_element_count, ArrayType::Normal, - 0).getAsOpaquePtr()); + 0)); } } } - return ClangASTType(); + return CompilerType(); } -ClangASTType +CompilerType ClangASTContext::GetOrCreateStructForIdentifier (const ConstString &type_name, - const std::initializer_list< std::pair < const char *, ClangASTType > >& type_fields, + const std::initializer_list< std::pair < const char *, CompilerType > >& type_fields, bool packed) { - ClangASTType type; + CompilerType type; if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)).IsValid()) return type; type = CreateRecordType(nullptr, lldb::eAccessPublic, type_name.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC); - type.StartTagDeclarationDefinition(); + StartTagDeclarationDefinition(type); for (const auto& field : type_fields) - type.AddFieldToRecordType(field.first, field.second, lldb::eAccessPublic, 0); + AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic, 0); if (packed) - type.SetIsPacked(); - type.CompleteTagDeclarationDefinition(); + SetIsPacked(type); + CompleteTagDeclarationDefinition(type); return type; } #pragma mark Enumeration Types -ClangASTType -ClangASTContext::CreateEnumerationType +CompilerType +ClangASTContext::CreateEnumerationType ( - const char *name, - DeclContext *decl_ctx, - const Declaration &decl, - const ClangASTType &integer_clang_type -) + const char *name, + DeclContext *decl_ctx, + const Declaration &decl, + const CompilerType &integer_clang_type + ) { // TODO: Do something intelligent with the Declaration object passed in // like maybe filling in the SourceLocation with it... ASTContext *ast = getASTContext(); - + // TODO: ask about these... -// const bool IsScoped = false; -// const bool IsFixed = false; - + // const bool IsScoped = false; + // const bool IsFixed = false; + EnumDecl *enum_decl = EnumDecl::Create (*ast, decl_ctx, SourceLocation(), @@ -1934,13 +2171,13 @@ ClangASTContext::CreateEnumerationType if (enum_decl) { // TODO: check if we should be setting the promotion type too? - enum_decl->setIntegerType(integer_clang_type.GetQualType()); + enum_decl->setIntegerType(GetQualType(integer_clang_type)); enum_decl->setAccess(AS_public); // TODO respect what's in the debug info - return ClangASTType (ast, ast->getTagDeclType(enum_decl).getAsOpaquePtr()); + return CompilerType (ast, ast->getTagDeclType(enum_decl)); } - return ClangASTType(); + return CompilerType(); } // Disable this for now since I can't seem to get a nicely formatted float @@ -1950,7 +2187,7 @@ ClangASTContext::CreateEnumerationType // so we can support remote targets. The code below also requires a patch to // llvm::APInt. //bool -//ClangASTContext::ConvertFloatValueToString (ASTContext *ast, clang_type_t clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str) +//ClangASTContext::ConvertFloatValueToString (ASTContext *ast, lldb::opaque_compiler_type_t 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; @@ -1984,7 +2221,7 @@ ClangASTContext::CreateEnumerationType // return false; //} -ClangASTType +CompilerType ClangASTContext::GetIntTypeFromBitSize (clang::ASTContext *ast, size_t bit_size, bool is_signed) { @@ -1993,74 +2230,207 @@ ClangASTContext::GetIntTypeFromBitSize (clang::ASTContext *ast, if (is_signed) { if (bit_size == ast->getTypeSize(ast->SignedCharTy)) - return ClangASTType(ast, ast->SignedCharTy.getAsOpaquePtr()); + return CompilerType(ast, ast->SignedCharTy); if (bit_size == ast->getTypeSize(ast->ShortTy)) - return ClangASTType(ast, ast->ShortTy.getAsOpaquePtr()); + return CompilerType(ast, ast->ShortTy); if (bit_size == ast->getTypeSize(ast->IntTy)) - return ClangASTType(ast, ast->IntTy.getAsOpaquePtr()); + return CompilerType(ast, ast->IntTy); if (bit_size == ast->getTypeSize(ast->LongTy)) - return ClangASTType(ast, ast->LongTy.getAsOpaquePtr()); + return CompilerType(ast, ast->LongTy); if (bit_size == ast->getTypeSize(ast->LongLongTy)) - return ClangASTType(ast, ast->LongLongTy.getAsOpaquePtr()); + return CompilerType(ast, ast->LongLongTy); if (bit_size == ast->getTypeSize(ast->Int128Ty)) - return ClangASTType(ast, ast->Int128Ty.getAsOpaquePtr()); + return CompilerType(ast, ast->Int128Ty); } else { if (bit_size == ast->getTypeSize(ast->UnsignedCharTy)) - return ClangASTType(ast, ast->UnsignedCharTy.getAsOpaquePtr()); + return CompilerType(ast, ast->UnsignedCharTy); if (bit_size == ast->getTypeSize(ast->UnsignedShortTy)) - return ClangASTType(ast, ast->UnsignedShortTy.getAsOpaquePtr()); + return CompilerType(ast, ast->UnsignedShortTy); if (bit_size == ast->getTypeSize(ast->UnsignedIntTy)) - return ClangASTType(ast, ast->UnsignedIntTy.getAsOpaquePtr()); + return CompilerType(ast, ast->UnsignedIntTy); if (bit_size == ast->getTypeSize(ast->UnsignedLongTy)) - return ClangASTType(ast, ast->UnsignedLongTy.getAsOpaquePtr()); + return CompilerType(ast, ast->UnsignedLongTy); if (bit_size == ast->getTypeSize(ast->UnsignedLongLongTy)) - return ClangASTType(ast, ast->UnsignedLongLongTy.getAsOpaquePtr()); + return CompilerType(ast, ast->UnsignedLongLongTy); if (bit_size == ast->getTypeSize(ast->UnsignedInt128Ty)) - return ClangASTType(ast, ast->UnsignedInt128Ty.getAsOpaquePtr()); + return CompilerType(ast, ast->UnsignedInt128Ty); } } - return ClangASTType(); + return CompilerType(); } -ClangASTType +CompilerType ClangASTContext::GetPointerSizedIntType (clang::ASTContext *ast, bool is_signed) { if (ast) return GetIntTypeFromBitSize(ast, ast->getTypeSize(ast->VoidPtrTy), is_signed); - return ClangASTType(); + return CompilerType(); } -ClangASTType -ClangASTContext::GetFloatTypeFromBitSize (clang::ASTContext *ast, - size_t bit_size) +void +ClangASTContext::DumpDeclContextHiearchy (clang::DeclContext *decl_ctx) { - if (ast) + if (decl_ctx) + { + DumpDeclContextHiearchy (decl_ctx->getParent()); + + clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl_ctx); + if (named_decl) + { + printf ("%20s: %s\n", decl_ctx->getDeclKindName(), named_decl->getDeclName().getAsString().c_str()); + } + else + { + printf ("%20s\n", decl_ctx->getDeclKindName()); + } + } +} + +void +ClangASTContext::DumpDeclHiearchy (clang::Decl *decl) +{ + if (decl == nullptr) + return; + DumpDeclContextHiearchy(decl->getDeclContext()); + + clang::RecordDecl *record_decl = llvm::dyn_cast<clang::RecordDecl>(decl); + if (record_decl) { - if (bit_size == ast->getTypeSize(ast->FloatTy)) - return ClangASTType(ast, ast->FloatTy.getAsOpaquePtr()); - else if (bit_size == ast->getTypeSize(ast->DoubleTy)) - return ClangASTType(ast, ast->DoubleTy.getAsOpaquePtr()); - else if (bit_size == ast->getTypeSize(ast->LongDoubleTy)) - return ClangASTType(ast, ast->LongDoubleTy.getAsOpaquePtr()); - else if (bit_size == ast->getTypeSize(ast->HalfTy)) - return ClangASTType(ast, ast->HalfTy.getAsOpaquePtr()); + printf ("%20s: %s%s\n", decl->getDeclKindName(), record_decl->getDeclName().getAsString().c_str(), record_decl->isInjectedClassName() ? " (injected class name)" : ""); + + } + else + { + clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl); + if (named_decl) + { + printf ("%20s: %s\n", decl->getDeclKindName(), named_decl->getDeclName().getAsString().c_str()); + } + else + { + printf ("%20s\n", decl->getDeclKindName()); + } } - return ClangASTType(); } bool +ClangASTContext::DeclsAreEquivalent (clang::Decl *lhs_decl, clang::Decl *rhs_decl) +{ + if (lhs_decl && rhs_decl) + { + //---------------------------------------------------------------------- + // Make sure the decl kinds match first + //---------------------------------------------------------------------- + const clang::Decl::Kind lhs_decl_kind = lhs_decl->getKind(); + const clang::Decl::Kind rhs_decl_kind = rhs_decl->getKind(); + + if (lhs_decl_kind == rhs_decl_kind) + { + //------------------------------------------------------------------ + // Now check that the decl contexts kinds are all equivalent + // before we have to check any names of the decl contexts... + //------------------------------------------------------------------ + clang::DeclContext *lhs_decl_ctx = lhs_decl->getDeclContext(); + clang::DeclContext *rhs_decl_ctx = rhs_decl->getDeclContext(); + if (lhs_decl_ctx && rhs_decl_ctx) + { + while (1) + { + if (lhs_decl_ctx && rhs_decl_ctx) + { + const clang::Decl::Kind lhs_decl_ctx_kind = lhs_decl_ctx->getDeclKind(); + const clang::Decl::Kind rhs_decl_ctx_kind = rhs_decl_ctx->getDeclKind(); + if (lhs_decl_ctx_kind == rhs_decl_ctx_kind) + { + lhs_decl_ctx = lhs_decl_ctx->getParent(); + rhs_decl_ctx = rhs_decl_ctx->getParent(); + + if (lhs_decl_ctx == nullptr && rhs_decl_ctx == nullptr) + break; + } + else + return false; + } + else + return false; + } + + //-------------------------------------------------------------- + // Now make sure the name of the decls match + //-------------------------------------------------------------- + clang::NamedDecl *lhs_named_decl = llvm::dyn_cast<clang::NamedDecl>(lhs_decl); + clang::NamedDecl *rhs_named_decl = llvm::dyn_cast<clang::NamedDecl>(rhs_decl); + if (lhs_named_decl && rhs_named_decl) + { + clang::DeclarationName lhs_decl_name = lhs_named_decl->getDeclName(); + clang::DeclarationName rhs_decl_name = rhs_named_decl->getDeclName(); + if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) + { + if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString()) + return false; + } + else + return false; + } + else + return false; + + //-------------------------------------------------------------- + // We know that the decl context kinds all match, so now we need + // to make sure the names match as well + //-------------------------------------------------------------- + lhs_decl_ctx = lhs_decl->getDeclContext(); + rhs_decl_ctx = rhs_decl->getDeclContext(); + while (1) + { + switch (lhs_decl_ctx->getDeclKind()) + { + case clang::Decl::TranslationUnit: + // We don't care about the translation unit names + return true; + default: + { + clang::NamedDecl *lhs_named_decl = llvm::dyn_cast<clang::NamedDecl>(lhs_decl_ctx); + clang::NamedDecl *rhs_named_decl = llvm::dyn_cast<clang::NamedDecl>(rhs_decl_ctx); + if (lhs_named_decl && rhs_named_decl) + { + clang::DeclarationName lhs_decl_name = lhs_named_decl->getDeclName(); + clang::DeclarationName rhs_decl_name = rhs_named_decl->getDeclName(); + if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) + { + if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString()) + return false; + } + else + return false; + } + else + return false; + } + break; + + } + lhs_decl_ctx = lhs_decl_ctx->getParent(); + rhs_decl_ctx = rhs_decl_ctx->getParent(); + } + } + } + } + return false; +} +bool ClangASTContext::GetCompleteDecl (clang::ASTContext *ast, clang::Decl *decl) { @@ -2148,46 +2518,7484 @@ ClangASTContext::GetAsDeclContext (clang::ObjCMethodDecl *objc_method_decl) return llvm::dyn_cast<clang::DeclContext>(objc_method_decl); } +bool +ClangASTContext::SetTagTypeKind (clang::QualType tag_qual_type, int kind) const +{ + const clang::Type *clang_type = tag_qual_type.getTypePtr(); + if (clang_type) + { + const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(clang_type); + if (tag_type) + { + clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(tag_type->getDecl()); + if (tag_decl) + { + tag_decl->setTagKind ((clang::TagDecl::TagKind)kind); + return true; + } + } + } + return false; +} + bool -ClangASTContext::GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx, - lldb::LanguageType &language, - bool &is_instance_method, - ConstString &language_object_name) +ClangASTContext::SetDefaultAccessForRecordFields (clang::RecordDecl* record_decl, + int default_accessibility, + int *assigned_accessibilities, + size_t num_assigned_accessibilities) { - language_object_name.Clear(); - language = eLanguageTypeUnknown; - is_instance_method = false; + if (record_decl) + { + uint32_t field_idx; + clang::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 ((clang::AccessSpecifier)default_accessibility); + } + return true; + } + return false; +} - if (decl_ctx) +clang::DeclContext * +ClangASTContext::GetDeclContextForType (const CompilerType& type) +{ + return GetDeclContextForType(GetQualType(type)); +} + +clang::DeclContext * +ClangASTContext::GetDeclContextForType (clang::QualType type) +{ + if (type.isNull()) + return nullptr; + + clang::QualType qual_type = type.getCanonicalType(); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::ObjCInterface: return llvm::cast<clang::ObjCObjectType>(qual_type.getTypePtr())->getInterface(); + case clang::Type::ObjCObjectPointer: return GetDeclContextForType (llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType()); + case clang::Type::Record: return llvm::cast<clang::RecordType>(qual_type)->getDecl(); + case clang::Type::Enum: return llvm::cast<clang::EnumType>(qual_type)->getDecl(); + case clang::Type::Typedef: return GetDeclContextForType (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()); + case clang::Type::Auto: return GetDeclContextForType (llvm::cast<clang::AutoType>(qual_type)->getDeducedType()); + case clang::Type::Elaborated: return GetDeclContextForType (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()); + case clang::Type::Paren: return GetDeclContextForType (llvm::cast<clang::ParenType>(qual_type)->desugar()); + default: + break; + } + // No DeclContext in this type... + return nullptr; +} + +static bool +GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type, bool allow_completion = true) +{ + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::ConstantArray: + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + { + const clang::ArrayType *array_type = llvm::dyn_cast<clang::ArrayType>(qual_type.getTypePtr()); + + if (array_type) + return GetCompleteQualType (ast, array_type->getElementType(), allow_completion); + } + break; + case clang::Type::Record: + { + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + if (cxx_record_decl->hasExternalLexicalStorage()) + { + const bool is_complete = cxx_record_decl->isCompleteDefinition(); + const bool fields_loaded = cxx_record_decl->hasLoadedFieldsFromExternalStorage(); + if (is_complete && fields_loaded) + return true; + + if (!allow_completion) + return false; + + // Call the field_begin() accessor to for it to use the external source + // to load the fields... + clang::ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (external_ast_source) + { + external_ast_source->CompleteType(cxx_record_decl); + if (cxx_record_decl->isCompleteDefinition()) + { + cxx_record_decl->setHasLoadedFieldsFromExternalStorage (true); + cxx_record_decl->field_begin(); + } + } + } + } + const clang::TagType *tag_type = llvm::cast<clang::TagType>(qual_type.getTypePtr()); + return !tag_type->isIncompleteType(); + } + break; + + case clang::Type::Enum: + { + const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()); + if (tag_type) + { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + { + if (tag_decl->getDefinition()) + return true; + + if (!allow_completion) + return false; + + if (tag_decl->hasExternalLexicalStorage()) + { + if (ast) + { + clang::ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (external_ast_source) + { + external_ast_source->CompleteType(tag_decl); + return !tag_type->isIncompleteType(); + } + } + } + return false; + } + } + + } + break; + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added ASTContext + // because it only supports TagDecl objects right now... + if (class_interface_decl) + { + if (class_interface_decl->getDefinition()) + return true; + + if (!allow_completion) + return false; + + if (class_interface_decl->hasExternalLexicalStorage()) + { + if (ast) + { + clang::ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (external_ast_source) + { + external_ast_source->CompleteType (class_interface_decl); + return !objc_class_type->isIncompleteType(); + } + } + } + return false; + } + } + } + break; + + case clang::Type::Typedef: + return GetCompleteQualType (ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType(), allow_completion); + + case clang::Type::Auto: + return GetCompleteQualType (ast, llvm::cast<clang::AutoType>(qual_type)->getDeducedType(), allow_completion); + + case clang::Type::Elaborated: + return GetCompleteQualType (ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType(), allow_completion); + + case clang::Type::Paren: + return GetCompleteQualType (ast, llvm::cast<clang::ParenType>(qual_type)->desugar(), allow_completion); + + case clang::Type::Attributed: + return GetCompleteQualType (ast, llvm::cast<clang::AttributedType>(qual_type)->getModifiedType(), allow_completion); + + default: + break; + } + + return true; +} + +static clang::ObjCIvarDecl::AccessControl +ConvertAccessTypeToObjCIvarAccessControl (AccessType access) +{ + switch (access) + { + case eAccessNone: return clang::ObjCIvarDecl::None; + case eAccessPublic: return clang::ObjCIvarDecl::Public; + case eAccessPrivate: return clang::ObjCIvarDecl::Private; + case eAccessProtected: return clang::ObjCIvarDecl::Protected; + case eAccessPackage: return clang::ObjCIvarDecl::Package; + } + return clang::ObjCIvarDecl::None; +} + + +//---------------------------------------------------------------------- +// Tests +//---------------------------------------------------------------------- + +bool +ClangASTContext::IsAggregateType (lldb::opaque_compiler_type_t type) +{ + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + case clang::Type::ConstantArray: + case clang::Type::ExtVector: + case clang::Type::Vector: + case clang::Type::Record: + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + return true; + case clang::Type::Auto: + return IsAggregateType(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr()); + case clang::Type::Elaborated: + return IsAggregateType(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr()); + case clang::Type::Typedef: + return IsAggregateType(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr()); + case clang::Type::Paren: + return IsAggregateType(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()); + default: + break; + } + // The clang type does have a value + return false; +} + +bool +ClangASTContext::IsAnonymousType (lldb::opaque_compiler_type_t type) +{ + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + { + if (const clang::RecordType *record_type = llvm::dyn_cast_or_null<clang::RecordType>(qual_type.getTypePtrOrNull())) + { + if (const clang::RecordDecl *record_decl = record_type->getDecl()) + { + return record_decl->isAnonymousStructOrUnion(); + } + } + break; + } + case clang::Type::Auto: + return IsAnonymousType(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr()); + case clang::Type::Elaborated: + return IsAnonymousType(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr()); + case clang::Type::Typedef: + return IsAnonymousType(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr()); + case clang::Type::Paren: + return IsAnonymousType(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()); + default: + break; + } + // The clang type does have a value + return false; +} + +bool +ClangASTContext::IsArrayType (lldb::opaque_compiler_type_t type, + CompilerType *element_type_ptr, + uint64_t *size, + bool *is_incomplete) +{ + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + default: + break; + + case clang::Type::ConstantArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType (getASTContext(), llvm::cast<clang::ConstantArrayType>(qual_type)->getElementType()); + if (size) + *size = llvm::cast<clang::ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULLONG_MAX); + if (is_incomplete) + *is_incomplete = false; + return true; + + case clang::Type::IncompleteArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType (getASTContext(), llvm::cast<clang::IncompleteArrayType>(qual_type)->getElementType()); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = true; + return true; + + case clang::Type::VariableArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType (getASTContext(), llvm::cast<clang::VariableArrayType>(qual_type)->getElementType()); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + return true; + + case clang::Type::DependentSizedArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType (getASTContext(), llvm::cast<clang::DependentSizedArrayType>(qual_type)->getElementType()); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + return true; + + case clang::Type::Typedef: + return IsArrayType(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), + element_type_ptr, + size, + is_incomplete); + case clang::Type::Auto: + return IsArrayType(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), + element_type_ptr, + size, + is_incomplete); + case clang::Type::Elaborated: + return IsArrayType(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), + element_type_ptr, + size, + is_incomplete); + case clang::Type::Paren: + return IsArrayType(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), + element_type_ptr, + size, + is_incomplete); + } + if (element_type_ptr) + element_type_ptr->Clear(); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + return false; +} + +bool +ClangASTContext::IsVectorType (lldb::opaque_compiler_type_t type, + CompilerType *element_type, + uint64_t *size) +{ + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Vector: + { + const clang::VectorType *vector_type = qual_type->getAs<clang::VectorType>(); + if (vector_type) + { + if (size) + *size = vector_type->getNumElements(); + if (element_type) + *element_type = CompilerType(getASTContext(), vector_type->getElementType()); + } + return true; + } + break; + case clang::Type::ExtVector: + { + const clang::ExtVectorType *ext_vector_type = qual_type->getAs<clang::ExtVectorType>(); + if (ext_vector_type) + { + if (size) + *size = ext_vector_type->getNumElements(); + if (element_type) + *element_type = CompilerType(getASTContext(), ext_vector_type->getElementType()); + } + return true; + } + default: + break; + } + return false; +} + +bool +ClangASTContext::IsRuntimeGeneratedType (lldb::opaque_compiler_type_t type) +{ + clang::DeclContext* decl_ctx = ClangASTContext::GetASTContext(getASTContext())->GetDeclContextForType(GetQualType(type)); + if (!decl_ctx) + return false; + + if (!llvm::isa<clang::ObjCInterfaceDecl>(decl_ctx)) + return false; + + clang::ObjCInterfaceDecl *result_iface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx); + + ClangASTMetadata* ast_metadata = ClangASTContext::GetMetadata(getASTContext(), result_iface_decl); + if (!ast_metadata) + return false; + return (ast_metadata->GetISAPtr() != 0); +} + +bool +ClangASTContext::IsCharType (lldb::opaque_compiler_type_t type) +{ + return GetQualType(type).getUnqualifiedType()->isCharType(); +} + + +bool +ClangASTContext::IsCompleteType (lldb::opaque_compiler_type_t type) +{ + const bool allow_completion = false; + return GetCompleteQualType (getASTContext(), GetQualType(type), allow_completion); +} + +bool +ClangASTContext::IsConst(lldb::opaque_compiler_type_t type) +{ + return GetQualType(type).isConstQualified(); +} + +bool +ClangASTContext::IsCStringType (lldb::opaque_compiler_type_t type, uint32_t &length) +{ + CompilerType pointee_or_element_clang_type; + length = 0; + Flags type_flags (GetTypeInfo (type, &pointee_or_element_clang_type)); + + if (!pointee_or_element_clang_type.IsValid()) + return false; + + if (type_flags.AnySet (eTypeIsArray | eTypeIsPointer)) + { + if (pointee_or_element_clang_type.IsCharType()) + { + if (type_flags.Test (eTypeIsArray)) + { + // We know the size of the array and it could be a C string + // since it is an array of characters + length = llvm::cast<clang::ConstantArrayType>(GetCanonicalQualType(type).getTypePtr())->getSize().getLimitedValue(); + } + return true; + + } + } + return false; +} + +bool +ClangASTContext::IsFunctionType (lldb::opaque_compiler_type_t type, bool *is_variadic_ptr) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + + if (qual_type->isFunctionType()) + { + if (is_variadic_ptr) + { + const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (function_proto_type) + *is_variadic_ptr = function_proto_type->isVariadic(); + else + *is_variadic_ptr = false; + } + return true; + } + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + default: + break; + case clang::Type::Typedef: + return IsFunctionType(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), nullptr); + case clang::Type::Auto: + return IsFunctionType(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), nullptr); + case clang::Type::Elaborated: + return IsFunctionType(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), nullptr); + case clang::Type::Paren: + return IsFunctionType(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), nullptr); + case clang::Type::LValueReference: + case clang::Type::RValueReference: + { + const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + if (reference_type) + return IsFunctionType(reference_type->getPointeeType().getAsOpaquePtr(), nullptr); + } + break; + } + } + return false; +} + +// Used to detect "Homogeneous Floating-point Aggregates" +uint32_t +ClangASTContext::IsHomogeneousAggregate (lldb::opaque_compiler_type_t type, CompilerType* base_type_ptr) +{ + if (!type) + return 0; + + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType (type)) + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + if (cxx_record_decl->getNumBases() || + cxx_record_decl->isDynamicClass()) + return 0; + } + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + if (record_type) + { + const clang::RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) + { + // We are looking for a structure that contains only floating point types + clang::RecordDecl::field_iterator field_pos, field_end = record_decl->field_end(); + uint32_t num_fields = 0; + bool is_hva = false; + bool is_hfa = false; + clang::QualType base_qual_type; + for (field_pos = record_decl->field_begin(); field_pos != field_end; ++field_pos) + { + clang::QualType field_qual_type = field_pos->getType(); + if (field_qual_type->isFloatingType()) + { + if (field_qual_type->isComplexType()) + return 0; + else + { + if (num_fields == 0) + base_qual_type = field_qual_type; + else + { + if (is_hva) + return 0; + is_hfa = true; + if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr()) + return 0; + } + } + } + else if (field_qual_type->isVectorType() || field_qual_type->isExtVectorType()) + { + const clang::VectorType *array = field_qual_type.getTypePtr()->getAs<clang::VectorType>(); + if (array && array->getNumElements() <= 4) + { + if (num_fields == 0) + base_qual_type = array->getElementType(); + else + { + if (is_hfa) + return 0; + is_hva = true; + if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr()) + return 0; + } + } + else + return 0; + } + else + return 0; + ++num_fields; + } + if (base_type_ptr) + *base_type_ptr = CompilerType (getASTContext(), base_qual_type); + return num_fields; + } + } + } + break; + + case clang::Type::Typedef: + return IsHomogeneousAggregate(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), base_type_ptr); + + case clang::Type::Auto: + return IsHomogeneousAggregate(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), base_type_ptr); + + case clang::Type::Elaborated: + return IsHomogeneousAggregate(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), base_type_ptr); + default: + break; + } + return 0; +} + +size_t +ClangASTContext::GetNumberOfFunctionArguments (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (func) + return func->getNumParams(); + } + return 0; +} + +CompilerType +ClangASTContext::GetFunctionArgumentAtIndex (lldb::opaque_compiler_type_t type, const size_t index) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (func) + { + if (index < func->getNumParams()) + return CompilerType(getASTContext(), func->getParamType(index)); + } + } + return CompilerType(); +} + +bool +ClangASTContext::IsFunctionPointerType (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + + if (qual_type->isFunctionPointerType()) + return true; + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + default: + break; + case clang::Type::Typedef: + return IsFunctionPointerType (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr()); + case clang::Type::Auto: + return IsFunctionPointerType (llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr()); + case clang::Type::Elaborated: + return IsFunctionPointerType (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr()); + case clang::Type::Paren: + return IsFunctionPointerType (llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()); + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + { + const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + if (reference_type) + return IsFunctionPointerType(reference_type->getPointeeType().getAsOpaquePtr()); + } + break; + } + } + return false; + +} + +bool +ClangASTContext::IsIntegerType (lldb::opaque_compiler_type_t type, bool &is_signed) +{ + if (!type) + return false; + + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal()); + + if (builtin_type) + { + if (builtin_type->isInteger()) + { + is_signed = builtin_type->isSignedInteger(); + return true; + } + } + + return false; +} + +bool +ClangASTContext::IsPointerType (lldb::opaque_compiler_type_t type, CompilerType *pointee_type) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + default: + break; + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + return true; + } + return false; + case clang::Type::ObjCObjectPointer: + if (pointee_type) + pointee_type->SetCompilerType (getASTContext(), llvm::cast<clang::ObjCObjectPointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::BlockPointer: + if (pointee_type) + pointee_type->SetCompilerType (getASTContext(), llvm::cast<clang::BlockPointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::Pointer: + if (pointee_type) + pointee_type->SetCompilerType (getASTContext(), llvm::cast<clang::PointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::MemberPointer: + if (pointee_type) + pointee_type->SetCompilerType (getASTContext(), llvm::cast<clang::MemberPointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::Typedef: + return IsPointerType (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), pointee_type); + case clang::Type::Auto: + return IsPointerType (llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), pointee_type); + case clang::Type::Elaborated: + return IsPointerType (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), pointee_type); + case clang::Type::Paren: + return IsPointerType (llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), pointee_type); + default: + break; + } + } + if (pointee_type) + pointee_type->Clear(); + return false; +} + + +bool +ClangASTContext::IsPointerOrReferenceType (lldb::opaque_compiler_type_t type, CompilerType *pointee_type) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + default: + break; + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + return true; + } + return false; + case clang::Type::ObjCObjectPointer: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::ObjCObjectPointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::BlockPointer: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::BlockPointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::Pointer: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::PointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::MemberPointer: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::MemberPointerType>(qual_type)->getPointeeType()); + return true; + case clang::Type::LValueReference: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::LValueReferenceType>(qual_type)->desugar()); + return true; + case clang::Type::RValueReference: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::RValueReferenceType>(qual_type)->desugar()); + return true; + case clang::Type::Typedef: + return IsPointerOrReferenceType(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), pointee_type); + case clang::Type::Auto: + return IsPointerOrReferenceType(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), pointee_type); + case clang::Type::Elaborated: + return IsPointerOrReferenceType(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), pointee_type); + case clang::Type::Paren: + return IsPointerOrReferenceType(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), pointee_type); + default: + break; + } + } + if (pointee_type) + pointee_type->Clear(); + return false; +} + + +bool +ClangASTContext::IsReferenceType (lldb::opaque_compiler_type_t type, CompilerType *pointee_type, bool* is_rvalue) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + + switch (type_class) + { + case clang::Type::LValueReference: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::LValueReferenceType>(qual_type)->desugar()); + if (is_rvalue) + *is_rvalue = false; + return true; + case clang::Type::RValueReference: + if (pointee_type) + pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::RValueReferenceType>(qual_type)->desugar()); + if (is_rvalue) + *is_rvalue = true; + return true; + case clang::Type::Typedef: + return IsReferenceType (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), pointee_type, is_rvalue); + case clang::Type::Auto: + return IsReferenceType (llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), pointee_type, is_rvalue); + case clang::Type::Elaborated: + return IsReferenceType (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), pointee_type, is_rvalue); + case clang::Type::Paren: + return IsReferenceType (llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), pointee_type, is_rvalue); + + default: + break; + } + } + if (pointee_type) + pointee_type->Clear(); + return false; +} + +bool +ClangASTContext::IsFloatingPointType (lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + + if (const clang::BuiltinType *BT = llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal())) + { + clang::BuiltinType::Kind kind = BT->getKind(); + if (kind >= clang::BuiltinType::Float && kind <= clang::BuiltinType::LongDouble) + { + count = 1; + is_complex = false; + return true; + } + } + else if (const clang::ComplexType *CT = llvm::dyn_cast<clang::ComplexType>(qual_type->getCanonicalTypeInternal())) + { + if (IsFloatingPointType (CT->getElementType().getAsOpaquePtr(), count, is_complex)) + { + count = 2; + is_complex = true; + return true; + } + } + else if (const clang::VectorType *VT = llvm::dyn_cast<clang::VectorType>(qual_type->getCanonicalTypeInternal())) + { + if (IsFloatingPointType (VT->getElementType().getAsOpaquePtr(), count, is_complex)) + { + count = VT->getNumElements(); + is_complex = false; + return true; + } + } + } + count = 0; + is_complex = false; + return false; +} + + +bool +ClangASTContext::IsDefined(lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + + clang::QualType qual_type(GetQualType(type)); + const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()); + if (tag_type) + { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + return tag_decl->isCompleteDefinition(); + return false; + } + else + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + if (class_interface_decl) + return class_interface_decl->getDefinition() != nullptr; + return false; + } + } + return true; +} + +bool +ClangASTContext::IsObjCClassType (const CompilerType& type) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::ObjCObjectPointerType *obj_pointer_type = llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type); + + if (obj_pointer_type) + return obj_pointer_type->isObjCClassType(); + } + return false; +} + +bool +ClangASTContext::IsObjCObjectOrInterfaceType (const CompilerType& type) +{ + if (IsClangType(type)) + return GetCanonicalQualType(type)->isObjCObjectOrInterfaceType(); + return false; +} + +bool +ClangASTContext::IsPolymorphicClass (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) + { + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) + return cxx_record_decl->isPolymorphic(); + } + } + break; + + default: + break; + } + } + return false; +} + +bool +ClangASTContext::IsPossibleDynamicType (lldb::opaque_compiler_type_t type, CompilerType *dynamic_pointee_type, + bool check_cplusplus, + bool check_objc) +{ + clang::QualType pointee_qual_type; + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + bool success = false; + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Builtin: + if (check_objc && llvm::cast<clang::BuiltinType>(qual_type)->getKind() == clang::BuiltinType::ObjCId) + { + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType(this, type); + return true; + } + break; + + case clang::Type::ObjCObjectPointer: + if (check_objc) + { + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType(getASTContext(), llvm::cast<clang::ObjCObjectPointerType>(qual_type)->getPointeeType()); + return true; + } + break; + + case clang::Type::Pointer: + pointee_qual_type = llvm::cast<clang::PointerType>(qual_type)->getPointeeType(); + success = true; + break; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + pointee_qual_type = llvm::cast<clang::ReferenceType>(qual_type)->getPointeeType(); + success = true; + break; + + case clang::Type::Typedef: + return IsPossibleDynamicType (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), + dynamic_pointee_type, + check_cplusplus, + check_objc); + + case clang::Type::Auto: + return IsPossibleDynamicType (llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), + dynamic_pointee_type, + check_cplusplus, + check_objc); + + case clang::Type::Elaborated: + return IsPossibleDynamicType (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), + dynamic_pointee_type, + check_cplusplus, + check_objc); + + case clang::Type::Paren: + return IsPossibleDynamicType (llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), + dynamic_pointee_type, + check_cplusplus, + check_objc); + default: + break; + } + + if (success) + { + // Check to make sure what we are pointing too is a possible dynamic C++ type + // We currently accept any "void *" (in case we have a class that has been + // watered down to an opaque pointer) and virtual C++ classes. + const clang::Type::TypeClass pointee_type_class = pointee_qual_type.getCanonicalType()->getTypeClass(); + switch (pointee_type_class) + { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(pointee_qual_type)->getKind()) + { + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::Void: + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType(getASTContext(), pointee_qual_type); + return true; + default: + break; + } + break; + + case clang::Type::Record: + if (check_cplusplus) + { + clang::CXXRecordDecl *cxx_record_decl = pointee_qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + bool is_complete = cxx_record_decl->isCompleteDefinition(); + + if (is_complete) + success = cxx_record_decl->isDynamicClass(); + else + { + ClangASTMetadata *metadata = ClangASTContext::GetMetadata (getASTContext(), cxx_record_decl); + if (metadata) + success = metadata->GetIsDynamicCXXType(); + else + { + is_complete = CompilerType(getASTContext(), pointee_qual_type).GetCompleteType(); + if (is_complete) + success = cxx_record_decl->isDynamicClass(); + else + success = false; + } + } + + if (success) + { + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType(getASTContext(), pointee_qual_type); + return true; + } + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (check_objc) + { + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType(getASTContext(), pointee_qual_type); + return true; + } + break; + + default: + break; + } + } + } + if (dynamic_pointee_type) + dynamic_pointee_type->Clear(); + return false; +} + + +bool +ClangASTContext::IsScalarType (lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + + return (GetTypeInfo (type, nullptr) & eTypeIsScalar) != 0; +} + +bool +ClangASTContext::IsTypedefType (lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + return GetQualType(type)->getTypeClass() == clang::Type::Typedef; +} + +bool +ClangASTContext::IsVoidType (lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + return GetCanonicalQualType(type)->isVoidType(); +} + +bool +ClangASTContext::SupportsLanguage (lldb::LanguageType language) +{ + return ClangASTContextSupportsLanguage(language); +} + +bool +ClangASTContext::GetCXXClassName (const CompilerType& type, std::string &class_name) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + if (!qual_type.isNull()) + { + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + class_name.assign(cxx_record_decl->getIdentifier()->getNameStart()); + return true; + } + } + } + class_name.clear(); + return false; +} + + +bool +ClangASTContext::IsCXXClassType (const CompilerType& type) +{ + if (!type) + return false; + + clang::QualType qual_type (GetCanonicalQualType(type)); + if (!qual_type.isNull() && qual_type->getAsCXXRecordDecl() != nullptr) + return true; + return false; +} + +bool +ClangASTContext::IsBeingDefined (lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type); + if (tag_type) + return tag_type->isBeingDefined(); + return false; +} + +bool +ClangASTContext::IsObjCObjectPointerType (const CompilerType& type, CompilerType *class_type_ptr) +{ + if (!type) + return false; + + clang::QualType qual_type (GetCanonicalQualType(type)); + + if (!qual_type.isNull() && qual_type->isObjCObjectPointerType()) + { + if (class_type_ptr) + { + if (!qual_type->isObjCClassType() && + !qual_type->isObjCIdType()) + { + const clang::ObjCObjectPointerType *obj_pointer_type = llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type); + if (obj_pointer_type == nullptr) + class_type_ptr->Clear(); + else + class_type_ptr->SetCompilerType (type.GetTypeSystem(), clang::QualType(obj_pointer_type->getInterfaceType(), 0).getAsOpaquePtr()); + } + } + return true; + } + if (class_type_ptr) + class_type_ptr->Clear(); + return false; +} + +bool +ClangASTContext::GetObjCClassName (const CompilerType& type, std::string &class_name) +{ + if (!type) + return false; + + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::ObjCObjectType *object_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (object_type) + { + const clang::ObjCInterfaceDecl *interface = object_type->getInterface(); + if (interface) + { + class_name = interface->getNameAsString(); + return true; + } + } + return false; +} + + +//---------------------------------------------------------------------- +// Type Completion +//---------------------------------------------------------------------- + +bool +ClangASTContext::GetCompleteType (lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + const bool allow_completion = true; + return GetCompleteQualType (getASTContext(), GetQualType(type), allow_completion); +} + +ConstString +ClangASTContext::GetTypeName (lldb::opaque_compiler_type_t type) +{ + std::string type_name; + if (type) + { + clang::PrintingPolicy printing_policy (getASTContext()->getPrintingPolicy()); + clang::QualType qual_type(GetQualType(type)); + printing_policy.SuppressTagKeyword = true; + printing_policy.LangOpts.WChar = true; + const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (typedef_type) + { + const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + type_name = typedef_decl->getQualifiedNameAsString(); + } + else + { + type_name = qual_type.getAsString(printing_policy); + } + } + return ConstString(type_name); +} + +uint32_t +ClangASTContext::GetTypeInfo (lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_clang_type) +{ + if (!type) + return 0; + + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->Clear(); + + clang::QualType qual_type (GetQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Builtin: + { + const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal()); + + uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue; + switch (builtin_type->getKind()) + { + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), getASTContext()->ObjCBuiltinClassTy); + builtin_type_flags |= eTypeIsPointer | eTypeIsObjC; + break; + + case clang::BuiltinType::ObjCSel: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), getASTContext()->CharTy); + builtin_type_flags |= eTypeIsPointer | eTypeIsObjC; + break; + + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + builtin_type_flags |= eTypeIsScalar; + if (builtin_type->isInteger()) + { + builtin_type_flags |= eTypeIsInteger; + if (builtin_type->isSignedInteger()) + builtin_type_flags |= eTypeIsSigned; + } + else if (builtin_type->isFloatingPoint()) + builtin_type_flags |= eTypeIsFloat; + break; + default: + break; + } + return builtin_type_flags; + } + + case clang::Type::BlockPointer: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), qual_type->getPointeeType()); + return eTypeIsPointer | eTypeHasChildren | eTypeIsBlock; + + case clang::Type::Complex: + { + uint32_t complex_type_flags = eTypeIsBuiltIn | eTypeHasValue | eTypeIsComplex; + const clang::ComplexType *complex_type = llvm::dyn_cast<clang::ComplexType>(qual_type->getCanonicalTypeInternal()); + if (complex_type) + { + clang::QualType complex_element_type (complex_type->getElementType()); + if (complex_element_type->isIntegerType()) + complex_type_flags |= eTypeIsFloat; + else if (complex_element_type->isFloatingType()) + complex_type_flags |= eTypeIsInteger; + } + return complex_type_flags; + } + break; + + case clang::Type::ConstantArray: + case clang::Type::DependentSizedArray: + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), llvm::cast<clang::ArrayType>(qual_type.getTypePtr())->getElementType()); + return eTypeHasChildren | eTypeIsArray; + + case clang::Type::DependentName: return 0; + case clang::Type::DependentSizedExtVector: return eTypeHasChildren | eTypeIsVector; + case clang::Type::DependentTemplateSpecialization: return eTypeIsTemplate; + case clang::Type::Decltype: return 0; + + case clang::Type::Enum: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), llvm::cast<clang::EnumType>(qual_type)->getDecl()->getIntegerType()); + return eTypeIsEnumeration | eTypeHasValue; + + case clang::Type::Auto: + return CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetTypeInfo (pointee_or_element_clang_type); + case clang::Type::Elaborated: + return CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetTypeInfo (pointee_or_element_clang_type); + case clang::Type::Paren: + return CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetTypeInfo (pointee_or_element_clang_type); + + case clang::Type::FunctionProto: return eTypeIsFuncPrototype | eTypeHasValue; + case clang::Type::FunctionNoProto: return eTypeIsFuncPrototype | eTypeHasValue; + case clang::Type::InjectedClassName: return 0; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), llvm::cast<clang::ReferenceType>(qual_type.getTypePtr())->getPointeeType()); + return eTypeHasChildren | eTypeIsReference | eTypeHasValue; + + case clang::Type::MemberPointer: return eTypeIsPointer | eTypeIsMember | eTypeHasValue; + + case clang::Type::ObjCObjectPointer: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), qual_type->getPointeeType()); + return eTypeHasChildren | eTypeIsObjC | eTypeIsClass | eTypeIsPointer | eTypeHasValue; + + case clang::Type::ObjCObject: return eTypeHasChildren | eTypeIsObjC | eTypeIsClass; + case clang::Type::ObjCInterface: return eTypeHasChildren | eTypeIsObjC | eTypeIsClass; + + case clang::Type::Pointer: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType(getASTContext(), qual_type->getPointeeType()); + return eTypeHasChildren | eTypeIsPointer | eTypeHasValue; + + case clang::Type::Record: + if (qual_type->getAsCXXRecordDecl()) + return eTypeHasChildren | eTypeIsClass | eTypeIsCPlusPlus; + else + return eTypeHasChildren | eTypeIsStructUnion; + break; + case clang::Type::SubstTemplateTypeParm: return eTypeIsTemplate; + case clang::Type::TemplateTypeParm: return eTypeIsTemplate; + case clang::Type::TemplateSpecialization: return eTypeIsTemplate; + + case clang::Type::Typedef: + return eTypeIsTypedef | CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetTypeInfo (pointee_or_element_clang_type); + case clang::Type::TypeOfExpr: return 0; + case clang::Type::TypeOf: return 0; + case clang::Type::UnresolvedUsing: return 0; + + case clang::Type::ExtVector: + case clang::Type::Vector: + { + uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector; + const clang::VectorType *vector_type = llvm::dyn_cast<clang::VectorType>(qual_type->getCanonicalTypeInternal()); + if (vector_type) + { + if (vector_type->isIntegerType()) + vector_type_flags |= eTypeIsFloat; + else if (vector_type->isFloatingType()) + vector_type_flags |= eTypeIsInteger; + } + return vector_type_flags; + } + default: return 0; + } + return 0; +} + + + +lldb::LanguageType +ClangASTContext::GetMinimumLanguage (lldb::opaque_compiler_type_t type) +{ + if (!type) + return lldb::eLanguageTypeC; + + // If the type is a reference, then resolve it to what it refers to first: + clang::QualType qual_type (GetCanonicalQualType(type).getNonReferenceType()); + if (qual_type->isAnyPointerType()) + { + if (qual_type->isObjCObjectPointerType()) + return lldb::eLanguageTypeObjC; + + clang::QualType pointee_type (qual_type->getPointeeType()); + if (pointee_type->getPointeeCXXRecordDecl() != nullptr) + return lldb::eLanguageTypeC_plus_plus; + if (pointee_type->isObjCObjectOrInterfaceType()) + return lldb::eLanguageTypeObjC; + if (pointee_type->isObjCClassType()) + return lldb::eLanguageTypeObjC; + if (pointee_type.getTypePtr() == getASTContext()->ObjCBuiltinIdTy.getTypePtr()) + return lldb::eLanguageTypeObjC; + } + else + { + if (qual_type->isObjCObjectOrInterfaceType()) + return lldb::eLanguageTypeObjC; + if (qual_type->getAsCXXRecordDecl()) + return lldb::eLanguageTypeC_plus_plus; + switch (qual_type->getTypeClass()) + { + default: + break; + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + default: + case clang::BuiltinType::Void: + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + break; + + case clang::BuiltinType::NullPtr: + return eLanguageTypeC_plus_plus; + + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCSel: + return eLanguageTypeObjC; + + case clang::BuiltinType::Dependent: + case clang::BuiltinType::Overload: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::UnknownAny: + break; + } + break; + case clang::Type::Typedef: + return CompilerType(getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetMinimumLanguage(); + } + } + return lldb::eLanguageTypeC; +} + +lldb::TypeClass +ClangASTContext::GetTypeClass (lldb::opaque_compiler_type_t type) +{ + if (!type) + return lldb::eTypeClassInvalid; + + clang::QualType qual_type(GetQualType(type)); + + switch (qual_type->getTypeClass()) + { + case clang::Type::UnaryTransform: break; + case clang::Type::FunctionNoProto: return lldb::eTypeClassFunction; + case clang::Type::FunctionProto: return lldb::eTypeClassFunction; + case clang::Type::IncompleteArray: return lldb::eTypeClassArray; + case clang::Type::VariableArray: return lldb::eTypeClassArray; + case clang::Type::ConstantArray: return lldb::eTypeClassArray; + case clang::Type::DependentSizedArray: return lldb::eTypeClassArray; + case clang::Type::DependentSizedExtVector: return lldb::eTypeClassVector; + case clang::Type::ExtVector: return lldb::eTypeClassVector; + case clang::Type::Vector: return lldb::eTypeClassVector; + case clang::Type::Builtin: return lldb::eTypeClassBuiltin; + case clang::Type::ObjCObjectPointer: return lldb::eTypeClassObjCObjectPointer; + case clang::Type::BlockPointer: return lldb::eTypeClassBlockPointer; + case clang::Type::Pointer: return lldb::eTypeClassPointer; + case clang::Type::LValueReference: return lldb::eTypeClassReference; + case clang::Type::RValueReference: return lldb::eTypeClassReference; + case clang::Type::MemberPointer: return lldb::eTypeClassMemberPointer; + case clang::Type::Complex: + if (qual_type->isComplexType()) + return lldb::eTypeClassComplexFloat; + else + return lldb::eTypeClassComplexInteger; + case clang::Type::ObjCObject: return lldb::eTypeClassObjCObject; + case clang::Type::ObjCInterface: return lldb::eTypeClassObjCInterface; + case clang::Type::Record: + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + if (record_decl->isUnion()) + return lldb::eTypeClassUnion; + else if (record_decl->isStruct()) + return lldb::eTypeClassStruct; + else + return lldb::eTypeClassClass; + } + break; + case clang::Type::Enum: return lldb::eTypeClassEnumeration; + case clang::Type::Typedef: return lldb::eTypeClassTypedef; + case clang::Type::UnresolvedUsing: break; + case clang::Type::Paren: + return CompilerType(getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetTypeClass(); + case clang::Type::Auto: + return CompilerType(getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetTypeClass(); + case clang::Type::Elaborated: + return CompilerType(getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetTypeClass(); + + case clang::Type::Attributed: break; + case clang::Type::TemplateTypeParm: break; + case clang::Type::SubstTemplateTypeParm: break; + case clang::Type::SubstTemplateTypeParmPack:break; + case clang::Type::InjectedClassName: break; + case clang::Type::DependentName: break; + case clang::Type::DependentTemplateSpecialization: break; + case clang::Type::PackExpansion: break; + + case clang::Type::TypeOfExpr: break; + case clang::Type::TypeOf: break; + case clang::Type::Decltype: break; + case clang::Type::TemplateSpecialization: break; + case clang::Type::Atomic: break; + + // pointer type decayed from an array or function type. + case clang::Type::Decayed: break; + case clang::Type::Adjusted: break; + } + // We don't know hot to display this type... + return lldb::eTypeClassOther; + +} + +unsigned +ClangASTContext::GetTypeQualifiers(lldb::opaque_compiler_type_t type) +{ + if (type) + return GetQualType(type).getQualifiers().getCVRQualifiers(); + return 0; +} + +//---------------------------------------------------------------------- +// Creating related types +//---------------------------------------------------------------------- + +CompilerType +ClangASTContext::GetArrayElementType (lldb::opaque_compiler_type_t type, uint64_t *stride) +{ + if (type) + { + clang::QualType qual_type(GetCanonicalQualType(type)); + + const clang::Type *array_eletype = qual_type.getTypePtr()->getArrayElementTypeNoTypeQual(); + + if (!array_eletype) + return CompilerType(); + + CompilerType element_type (getASTContext(), array_eletype->getCanonicalTypeUnqualified()); + + // TODO: the real stride will be >= this value.. find the real one! + if (stride) + *stride = element_type.GetByteSize(nullptr); + + return element_type; + + } + return CompilerType(); +} + +CompilerType +ClangASTContext::GetCanonicalType (lldb::opaque_compiler_type_t type) +{ + if (type) + return CompilerType (getASTContext(), GetCanonicalQualType(type)); + return CompilerType(); +} + +static clang::QualType +GetFullyUnqualifiedType_Impl (clang::ASTContext *ast, clang::QualType qual_type) +{ + if (qual_type->isPointerType()) + qual_type = ast->getPointerType(GetFullyUnqualifiedType_Impl(ast, qual_type->getPointeeType())); + else + qual_type = qual_type.getUnqualifiedType(); + qual_type.removeLocalConst(); + qual_type.removeLocalRestrict(); + qual_type.removeLocalVolatile(); + return qual_type; +} + +CompilerType +ClangASTContext::GetFullyUnqualifiedType (lldb::opaque_compiler_type_t type) +{ + if (type) + return CompilerType(getASTContext(), GetFullyUnqualifiedType_Impl(getASTContext(), GetQualType(type))); + return CompilerType(); +} + + +int +ClangASTContext::GetFunctionArgumentCount (lldb::opaque_compiler_type_t type) +{ + if (type) + { + const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(GetCanonicalQualType(type)); + if (func) + return func->getNumParams(); + } + return -1; +} + +CompilerType +ClangASTContext::GetFunctionArgumentTypeAtIndex (lldb::opaque_compiler_type_t type, size_t idx) +{ + if (type) + { + const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(GetQualType(type)); + if (func) + { + const uint32_t num_args = func->getNumParams(); + if (idx < num_args) + return CompilerType(getASTContext(), func->getParamType(idx)); + } + } + return CompilerType(); +} + +CompilerType +ClangASTContext::GetFunctionReturnType (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType qual_type(GetQualType(type)); + const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (func) + return CompilerType(getASTContext(), func->getReturnType()); + } + return CompilerType(); +} + +size_t +ClangASTContext::GetNumMemberFunctions (lldb::opaque_compiler_type_t type) +{ + size_t num_functions = 0; + if (type) + { + clang::QualType qual_type(GetCanonicalQualType(type)); + switch (qual_type->getTypeClass()) { + case clang::Type::Record: + if (GetCompleteQualType (getASTContext(), qual_type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) + num_functions = std::distance(cxx_record_decl->method_begin(), cxx_record_decl->method_end()); + } + break; + + case clang::Type::ObjCObjectPointer: + if (GetCompleteType(type)) + { + const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType(); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl(); + if (class_interface_decl) + num_functions = std::distance(class_interface_decl->meth_begin(), class_interface_decl->meth_end()); + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + if (class_interface_decl) + num_functions = std::distance(class_interface_decl->meth_begin(), class_interface_decl->meth_end()); + } + } + break; + + + case clang::Type::Typedef: + return CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumMemberFunctions(); + + case clang::Type::Auto: + return CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetNumMemberFunctions(); + + case clang::Type::Elaborated: + return CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumMemberFunctions(); + + case clang::Type::Paren: + return CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumMemberFunctions(); + + default: + break; + } + } + return num_functions; +} + +TypeMemberFunctionImpl +ClangASTContext::GetMemberFunctionAtIndex (lldb::opaque_compiler_type_t type, size_t idx) +{ + std::string name; + MemberFunctionKind kind(MemberFunctionKind::eMemberFunctionKindUnknown); + CompilerType clang_type; + CompilerDecl clang_decl; + if (type) + { + clang::QualType qual_type(GetCanonicalQualType(type)); + switch (qual_type->getTypeClass()) { + case clang::Type::Record: + if (GetCompleteQualType (getASTContext(), qual_type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + auto method_iter = cxx_record_decl->method_begin(); + auto method_end = cxx_record_decl->method_end(); + if (idx < static_cast<size_t>(std::distance(method_iter, method_end))) + { + std::advance(method_iter, idx); + clang::CXXMethodDecl *cxx_method_decl = method_iter->getCanonicalDecl(); + if (cxx_method_decl) + { + name = cxx_method_decl->getDeclName().getAsString(); + if (cxx_method_decl->isStatic()) + kind = lldb::eMemberFunctionKindStaticMethod; + else if (llvm::isa<clang::CXXConstructorDecl>(cxx_method_decl)) + kind = lldb::eMemberFunctionKindConstructor; + else if (llvm::isa<clang::CXXDestructorDecl>(cxx_method_decl)) + kind = lldb::eMemberFunctionKindDestructor; + else + kind = lldb::eMemberFunctionKindInstanceMethod; + clang_type = CompilerType(this, cxx_method_decl->getType().getAsOpaquePtr()); + clang_decl = CompilerDecl(this, cxx_method_decl); + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + if (GetCompleteType(type)) + { + const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType(); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl(); + if (class_interface_decl) + { + auto method_iter = class_interface_decl->meth_begin(); + auto method_end = class_interface_decl->meth_end(); + if (idx < static_cast<size_t>(std::distance(method_iter, method_end))) + { + std::advance(method_iter, idx); + clang::ObjCMethodDecl *objc_method_decl = method_iter->getCanonicalDecl(); + if (objc_method_decl) + { + clang_decl = CompilerDecl(this, objc_method_decl); + name = objc_method_decl->getSelector().getAsString(); + if (objc_method_decl->isClassMethod()) + kind = lldb::eMemberFunctionKindStaticMethod; + else + kind = lldb::eMemberFunctionKindInstanceMethod; + } + } + } + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + if (class_interface_decl) + { + auto method_iter = class_interface_decl->meth_begin(); + auto method_end = class_interface_decl->meth_end(); + if (idx < static_cast<size_t>(std::distance(method_iter, method_end))) + { + std::advance(method_iter, idx); + clang::ObjCMethodDecl *objc_method_decl = method_iter->getCanonicalDecl(); + if (objc_method_decl) + { + clang_decl = CompilerDecl(this, objc_method_decl); + name = objc_method_decl->getSelector().getAsString(); + if (objc_method_decl->isClassMethod()) + kind = lldb::eMemberFunctionKindStaticMethod; + else + kind = lldb::eMemberFunctionKindInstanceMethod; + } + } + } + } + } + break; + + case clang::Type::Typedef: + return GetMemberFunctionAtIndex(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), idx); + + case clang::Type::Auto: + return GetMemberFunctionAtIndex(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), idx); + + case clang::Type::Elaborated: + return GetMemberFunctionAtIndex(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), idx); + + case clang::Type::Paren: + return GetMemberFunctionAtIndex(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), idx); + + default: + break; + } + } + + if (kind == eMemberFunctionKindUnknown) + return TypeMemberFunctionImpl(); + else + return TypeMemberFunctionImpl(clang_type, clang_decl, name, kind); +} + +CompilerType +ClangASTContext::GetNonReferenceType (lldb::opaque_compiler_type_t type) +{ + if (type) + return CompilerType(getASTContext(), GetQualType(type).getNonReferenceType()); + return CompilerType(); +} + +CompilerType +ClangASTContext::CreateTypedefType (const CompilerType& type, + const char *typedef_name, + const CompilerDeclContext &compiler_decl_ctx) +{ + if (type && typedef_name && typedef_name[0]) + { + ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (!ast) + return CompilerType(); + clang::ASTContext* clang_ast = ast->getASTContext(); + clang::QualType qual_type (GetQualType(type)); + + clang::DeclContext *decl_ctx = ClangASTContext::DeclContextGetAsDeclContext(compiler_decl_ctx); + if (decl_ctx == nullptr) + decl_ctx = ast->getASTContext()->getTranslationUnitDecl(); + + clang::TypedefDecl *decl = clang::TypedefDecl::Create (*clang_ast, + decl_ctx, + clang::SourceLocation(), + clang::SourceLocation(), + &clang_ast->Idents.get(typedef_name), + clang_ast->getTrivialTypeSourceInfo(qual_type)); + + decl->setAccess(clang::AS_public); // TODO respect proper access specifier + + // Get a uniqued clang::QualType for the typedef decl type + return CompilerType (clang_ast, clang_ast->getTypedefType (decl)); + } + return CompilerType(); + +} + +CompilerType +ClangASTContext::GetPointeeType (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType qual_type(GetQualType(type)); + return CompilerType (getASTContext(), qual_type.getTypePtr()->getPointeeType()); + } + return CompilerType(); +} + +CompilerType +ClangASTContext::GetPointerType (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType qual_type (GetQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + return CompilerType(getASTContext(), getASTContext()->getObjCObjectPointerType(qual_type)); + + default: + return CompilerType(getASTContext(), getASTContext()->getPointerType(qual_type)); + } + } + return CompilerType(); +} + + +CompilerType +ClangASTContext::GetLValueReferenceType (lldb::opaque_compiler_type_t type) +{ + if (type) + return CompilerType(this, getASTContext()->getLValueReferenceType(GetQualType(type)).getAsOpaquePtr()); + else + return CompilerType(); +} + +CompilerType +ClangASTContext::GetRValueReferenceType (lldb::opaque_compiler_type_t type) +{ + if (type) + return CompilerType(this, getASTContext()->getRValueReferenceType(GetQualType(type)).getAsOpaquePtr()); + else + return CompilerType(); +} + +CompilerType +ClangASTContext::AddConstModifier (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType result(GetQualType(type)); + result.addConst(); + return CompilerType (this, result.getAsOpaquePtr()); + } + return CompilerType(); +} + +CompilerType +ClangASTContext::AddVolatileModifier (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType result(GetQualType(type)); + result.addVolatile(); + return CompilerType (this, result.getAsOpaquePtr()); + } + return CompilerType(); + +} + +CompilerType +ClangASTContext::AddRestrictModifier (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType result(GetQualType(type)); + result.addRestrict(); + return CompilerType (this, result.getAsOpaquePtr()); + } + return CompilerType(); + +} + +CompilerType +ClangASTContext::CreateTypedef (lldb::opaque_compiler_type_t type, const char *typedef_name, const CompilerDeclContext &compiler_decl_ctx) +{ + if (type) + { + clang::ASTContext* clang_ast = getASTContext(); + clang::QualType qual_type (GetQualType(type)); + + clang::DeclContext *decl_ctx = ClangASTContext::DeclContextGetAsDeclContext(compiler_decl_ctx); + if (decl_ctx == nullptr) + decl_ctx = getASTContext()->getTranslationUnitDecl(); + + clang::TypedefDecl *decl = clang::TypedefDecl::Create (*clang_ast, + decl_ctx, + clang::SourceLocation(), + clang::SourceLocation(), + &clang_ast->Idents.get(typedef_name), + clang_ast->getTrivialTypeSourceInfo(qual_type)); + + decl->setAccess(clang::AS_public); // TODO respect proper access specifier + + // Get a uniqued clang::QualType for the typedef decl type + return CompilerType (this, clang_ast->getTypedefType (decl).getAsOpaquePtr()); + + } + return CompilerType(); + +} + +CompilerType +ClangASTContext::GetTypedefedType (lldb::opaque_compiler_type_t type) +{ + if (type) + { + const clang::TypedefType *typedef_type = llvm::dyn_cast<clang::TypedefType>(GetQualType(type)); + if (typedef_type) + return CompilerType (getASTContext(), typedef_type->getDecl()->getUnderlyingType()); + } + return CompilerType(); +} + +CompilerType +ClangASTContext::RemoveFastQualifiers (const CompilerType& type) +{ + if (IsClangType(type)) + { + clang::QualType qual_type(GetQualType(type)); + qual_type.getQualifiers().removeFastQualifiers(); + return CompilerType (type.GetTypeSystem(), qual_type.getAsOpaquePtr()); + } + return type; +} + + +//---------------------------------------------------------------------- +// Create related types using the current type's AST +//---------------------------------------------------------------------- + +CompilerType +ClangASTContext::GetBasicTypeFromAST (lldb::BasicType basic_type) +{ + return ClangASTContext::GetBasicType(getASTContext(), basic_type); +} +//---------------------------------------------------------------------- +// Exploring the type +//---------------------------------------------------------------------- + +uint64_t +ClangASTContext::GetBitSize (lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) +{ + if (GetCompleteType (type)) + { + clang::QualType qual_type(GetCanonicalQualType(type)); + switch (qual_type->getTypeClass()) + { + case clang::Type::ObjCInterface: + case clang::Type::ObjCObject: + { + ExecutionContext exe_ctx (exe_scope); + Process *process = exe_ctx.GetProcessPtr(); + if (process) + { + ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); + if (objc_runtime) + { + uint64_t bit_size = 0; + if (objc_runtime->GetTypeBitSize(CompilerType(getASTContext(), qual_type), bit_size)) + return bit_size; + } + } + else + { + static bool g_printed = false; + if (!g_printed) + { + StreamString s; + DumpTypeDescription(type, &s); + + llvm::outs() << "warning: trying to determine the size of type "; + llvm::outs() << s.GetString() << "\n"; + llvm::outs() << "without a valid ExecutionContext. this is not reliable. please file a bug against LLDB.\n"; + llvm::outs() << "backtrace:\n"; + llvm::sys::PrintStackTrace(llvm::outs()); + llvm::outs() << "\n"; + g_printed = true; + } + } + } + // fallthrough + default: + const uint32_t bit_size = getASTContext()->getTypeSize (qual_type); + if (bit_size == 0) + { + if (qual_type->isIncompleteArrayType()) + return getASTContext()->getTypeSize (qual_type->getArrayElementTypeNoTypeQual()->getCanonicalTypeUnqualified()); + } + if (qual_type->isObjCObjectOrInterfaceType()) + return bit_size + getASTContext()->getTypeSize(getASTContext()->ObjCBuiltinClassTy); + return bit_size; + } + } + return 0; +} + +size_t +ClangASTContext::GetTypeBitAlign (lldb::opaque_compiler_type_t type) +{ + if (GetCompleteType(type)) + return getASTContext()->getTypeAlign(GetQualType(type)); + return 0; +} + + +lldb::Encoding +ClangASTContext::GetEncoding (lldb::opaque_compiler_type_t type, uint64_t &count) +{ + if (!type) + return lldb::eEncodingInvalid; + + count = 1; + clang::QualType qual_type(GetCanonicalQualType(type)); + + switch (qual_type->getTypeClass()) + { + case clang::Type::UnaryTransform: + break; + + case clang::Type::FunctionNoProto: + case clang::Type::FunctionProto: + break; + + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + break; + + case clang::Type::ConstantArray: + break; + + case clang::Type::ExtVector: + case clang::Type::Vector: + // TODO: Set this to more than one??? + break; + + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + case clang::BuiltinType::Void: + break; + + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: return lldb::eEncodingSint; + + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: return lldb::eEncodingUint; + + case clang::BuiltinType::Half: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: return lldb::eEncodingIEEE754; + + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCSel: return lldb::eEncodingUint; + + case clang::BuiltinType::NullPtr: return lldb::eEncodingUint; + + case clang::BuiltinType::Kind::ARCUnbridgedCast: + case clang::BuiltinType::Kind::BoundMember: + case clang::BuiltinType::Kind::BuiltinFn: + case clang::BuiltinType::Kind::Dependent: + case clang::BuiltinType::Kind::OCLClkEvent: + case clang::BuiltinType::Kind::OCLEvent: + case clang::BuiltinType::Kind::OCLImage1d: + case clang::BuiltinType::Kind::OCLImage1dArray: + case clang::BuiltinType::Kind::OCLImage1dBuffer: + case clang::BuiltinType::Kind::OCLImage2d: + case clang::BuiltinType::Kind::OCLImage2dArray: + case clang::BuiltinType::Kind::OCLImage2dArrayDepth: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAA: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepth: + case clang::BuiltinType::Kind::OCLImage2dDepth: + case clang::BuiltinType::Kind::OCLImage2dMSAA: + case clang::BuiltinType::Kind::OCLImage2dMSAADepth: + case clang::BuiltinType::Kind::OCLImage3d: + case clang::BuiltinType::Kind::OCLQueue: + case clang::BuiltinType::Kind::OCLNDRange: + case clang::BuiltinType::Kind::OCLReserveID: + case clang::BuiltinType::Kind::OCLSampler: + case clang::BuiltinType::Kind::OMPArraySection: + case clang::BuiltinType::Kind::Overload: + case clang::BuiltinType::Kind::PseudoObject: + case clang::BuiltinType::Kind::UnknownAny: + break; + } + break; + // All pointer types are represented as unsigned integer encodings. + // We may nee to add a eEncodingPointer if we ever need to know the + // difference + case clang::Type::ObjCObjectPointer: + case clang::Type::BlockPointer: + case clang::Type::Pointer: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::MemberPointer: return lldb::eEncodingUint; + case clang::Type::Complex: + { + lldb::Encoding encoding = lldb::eEncodingIEEE754; + if (qual_type->isComplexType()) + encoding = lldb::eEncodingIEEE754; + else + { + const clang::ComplexType *complex_type = qual_type->getAsComplexIntegerType(); + if (complex_type) + encoding = CompilerType(getASTContext(), complex_type->getElementType()).GetEncoding(count); + else + encoding = lldb::eEncodingSint; + } + count = 2; + return encoding; + } + + case clang::Type::ObjCInterface: break; + case clang::Type::Record: break; + case clang::Type::Enum: return lldb::eEncodingSint; + case clang::Type::Typedef: + return CompilerType(getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetEncoding(count); + + case clang::Type::Auto: + return CompilerType(getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetEncoding(count); + + case clang::Type::Elaborated: + return CompilerType(getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetEncoding(count); + + case clang::Type::Paren: + return CompilerType(getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetEncoding(count); + + case clang::Type::DependentSizedArray: + case clang::Type::DependentSizedExtVector: + case clang::Type::UnresolvedUsing: + case clang::Type::Attributed: + case clang::Type::TemplateTypeParm: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::SubstTemplateTypeParmPack: + case clang::Type::InjectedClassName: + case clang::Type::DependentName: + case clang::Type::DependentTemplateSpecialization: + case clang::Type::PackExpansion: + case clang::Type::ObjCObject: + + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: + case clang::Type::TemplateSpecialization: + case clang::Type::Atomic: + case clang::Type::Adjusted: + break; + + // pointer type decayed from an array or function type. + case clang::Type::Decayed: + break; + } + count = 0; + return lldb::eEncodingInvalid; +} + +lldb::Format +ClangASTContext::GetFormat (lldb::opaque_compiler_type_t type) +{ + if (!type) + return lldb::eFormatDefault; + + clang::QualType qual_type(GetCanonicalQualType(type)); + + switch (qual_type->getTypeClass()) + { + case clang::Type::UnaryTransform: + break; + + case clang::Type::FunctionNoProto: + case clang::Type::FunctionProto: + break; + + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + break; + + case clang::Type::ConstantArray: + return lldb::eFormatVoid; // no value + + case clang::Type::ExtVector: + case clang::Type::Vector: + break; + + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + //default: assert(0 && "Unknown builtin type!"); + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::Void: + case clang::BuiltinType::BoundMember: + break; + + case clang::BuiltinType::Bool: return lldb::eFormatBoolean; + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: return lldb::eFormatChar; + case clang::BuiltinType::Char16: return lldb::eFormatUnicode16; + case clang::BuiltinType::Char32: return lldb::eFormatUnicode32; + case clang::BuiltinType::UShort: return lldb::eFormatUnsigned; + case clang::BuiltinType::Short: return lldb::eFormatDecimal; + case clang::BuiltinType::UInt: return lldb::eFormatUnsigned; + case clang::BuiltinType::Int: return lldb::eFormatDecimal; + case clang::BuiltinType::ULong: return lldb::eFormatUnsigned; + case clang::BuiltinType::Long: return lldb::eFormatDecimal; + case clang::BuiltinType::ULongLong: return lldb::eFormatUnsigned; + case clang::BuiltinType::LongLong: return lldb::eFormatDecimal; + case clang::BuiltinType::UInt128: return lldb::eFormatUnsigned; + case clang::BuiltinType::Int128: return lldb::eFormatDecimal; + case clang::BuiltinType::Half: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: return lldb::eFormatFloat; + default: + return lldb::eFormatHex; + } + break; + case clang::Type::ObjCObjectPointer: return lldb::eFormatHex; + case clang::Type::BlockPointer: return lldb::eFormatHex; + case clang::Type::Pointer: return lldb::eFormatHex; + case clang::Type::LValueReference: + case clang::Type::RValueReference: return lldb::eFormatHex; + case clang::Type::MemberPointer: break; + case clang::Type::Complex: + { + if (qual_type->isComplexType()) + return lldb::eFormatComplex; + else + return lldb::eFormatComplexInteger; + } + case clang::Type::ObjCInterface: break; + case clang::Type::Record: break; + case clang::Type::Enum: return lldb::eFormatEnum; + case clang::Type::Typedef: + return CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetFormat(); + case clang::Type::Auto: + return CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->desugar()).GetFormat(); + case clang::Type::Paren: + return CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetFormat(); + case clang::Type::Elaborated: + return CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetFormat(); + case clang::Type::DependentSizedArray: + case clang::Type::DependentSizedExtVector: + case clang::Type::UnresolvedUsing: + case clang::Type::Attributed: + case clang::Type::TemplateTypeParm: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::SubstTemplateTypeParmPack: + case clang::Type::InjectedClassName: + case clang::Type::DependentName: + case clang::Type::DependentTemplateSpecialization: + case clang::Type::PackExpansion: + case clang::Type::ObjCObject: + + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: + case clang::Type::TemplateSpecialization: + case clang::Type::Atomic: + case clang::Type::Adjusted: + break; + + // pointer type decayed from an array or function type. + case clang::Type::Decayed: + break; + } + // We don't know hot to display this type... + return lldb::eFormatBytes; +} + +static bool +ObjCDeclHasIVars (clang::ObjCInterfaceDecl *class_interface_decl, bool check_superclass) +{ + while (class_interface_decl) + { + if (class_interface_decl->ivar_size() > 0) + return true; + + if (check_superclass) + class_interface_decl = class_interface_decl->getSuperClass(); + else + break; + } + return false; +} + +uint32_t +ClangASTContext::GetNumChildren (lldb::opaque_compiler_type_t type, bool omit_empty_base_classes) +{ + if (!type) + return 0; + + uint32_t num_children = 0; + clang::QualType qual_type(GetQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + case clang::BuiltinType::ObjCId: // child is Class + case clang::BuiltinType::ObjCClass: // child is Class + num_children = 1; + break; + + default: + break; + } + break; + + case clang::Type::Complex: return 0; + + case clang::Type::Record: + if (GetCompleteQualType (getASTContext(), qual_type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::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. + clang::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 clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + + // Skip empty base classes + if (ClangASTContext::RecordHasFields(base_class_decl) == false) + continue; + + num_children++; + } + } + else + { + // Include all base classes + num_children += cxx_record_decl->getNumBases(); + } + + } + clang::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 clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteQualType (getASTContext(), qual_type)) + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + { + + clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + if (superclass_interface_decl) + { + if (omit_empty_base_classes) + { + if (ObjCDeclHasIVars (superclass_interface_decl, true)) + ++num_children; + } + else + ++num_children; + } + + num_children += class_interface_decl->ivar_size(); + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + { + const clang::ObjCObjectPointerType *pointer_type = llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr()); + clang::QualType pointee_type = pointer_type->getPointeeType(); + uint32_t num_pointee_children = CompilerType (getASTContext(),pointee_type).GetNumChildren (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 clang::Type::Vector: + case clang::Type::ExtVector: + num_children = llvm::cast<clang::VectorType>(qual_type.getTypePtr())->getNumElements(); + break; + + case clang::Type::ConstantArray: + num_children = llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue(); + break; + + case clang::Type::Pointer: + { + const clang::PointerType *pointer_type = llvm::cast<clang::PointerType>(qual_type.getTypePtr()); + clang::QualType pointee_type (pointer_type->getPointeeType()); + uint32_t num_pointee_children = CompilerType (getASTContext(),pointee_type).GetNumChildren (omit_empty_base_classes); + if (num_pointee_children == 0) + { + // We have a pointer to a pointee type that claims it has no children. + // We will want to look at + num_children = GetNumPointeeChildren (pointee_type); + } + else + num_children = num_pointee_children; + } + break; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + { + const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + clang::QualType pointee_type = reference_type->getPointeeType(); + uint32_t num_pointee_children = CompilerType (getASTContext(), pointee_type).GetNumChildren (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 clang::Type::Typedef: + num_children = CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumChildren (omit_empty_base_classes); + break; + + case clang::Type::Auto: + num_children = CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetNumChildren (omit_empty_base_classes); + break; + + case clang::Type::Elaborated: + num_children = CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumChildren (omit_empty_base_classes); + break; + + case clang::Type::Paren: + num_children = CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumChildren (omit_empty_base_classes); + break; + default: + break; + } + return num_children; +} + +CompilerType +ClangASTContext::GetBuiltinTypeByName (const ConstString &name) +{ + return GetBasicType (GetBasicTypeEnumeration (name)); +} + +lldb::BasicType +ClangASTContext::GetBasicTypeEnumeration (lldb::opaque_compiler_type_t type) +{ + if (type) + { + clang::QualType qual_type(GetQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + if (type_class == clang::Type::Builtin) + { + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + case clang::BuiltinType::Void: return eBasicTypeVoid; + case clang::BuiltinType::Bool: return eBasicTypeBool; + case clang::BuiltinType::Char_S: return eBasicTypeSignedChar; + case clang::BuiltinType::Char_U: return eBasicTypeUnsignedChar; + case clang::BuiltinType::Char16: return eBasicTypeChar16; + case clang::BuiltinType::Char32: return eBasicTypeChar32; + case clang::BuiltinType::UChar: return eBasicTypeUnsignedChar; + case clang::BuiltinType::SChar: return eBasicTypeSignedChar; + case clang::BuiltinType::WChar_S: return eBasicTypeSignedWChar; + case clang::BuiltinType::WChar_U: return eBasicTypeUnsignedWChar; + case clang::BuiltinType::Short: return eBasicTypeShort; + case clang::BuiltinType::UShort: return eBasicTypeUnsignedShort; + case clang::BuiltinType::Int: return eBasicTypeInt; + case clang::BuiltinType::UInt: return eBasicTypeUnsignedInt; + case clang::BuiltinType::Long: return eBasicTypeLong; + case clang::BuiltinType::ULong: return eBasicTypeUnsignedLong; + case clang::BuiltinType::LongLong: return eBasicTypeLongLong; + case clang::BuiltinType::ULongLong: return eBasicTypeUnsignedLongLong; + case clang::BuiltinType::Int128: return eBasicTypeInt128; + case clang::BuiltinType::UInt128: return eBasicTypeUnsignedInt128; + + case clang::BuiltinType::Half: return eBasicTypeHalf; + case clang::BuiltinType::Float: return eBasicTypeFloat; + case clang::BuiltinType::Double: return eBasicTypeDouble; + case clang::BuiltinType::LongDouble:return eBasicTypeLongDouble; + + case clang::BuiltinType::NullPtr: return eBasicTypeNullPtr; + case clang::BuiltinType::ObjCId: return eBasicTypeObjCID; + case clang::BuiltinType::ObjCClass: return eBasicTypeObjCClass; + case clang::BuiltinType::ObjCSel: return eBasicTypeObjCSel; + default: + return eBasicTypeOther; + } + } + } + return eBasicTypeInvalid; +} + +void +ClangASTContext::ForEachEnumerator (lldb::opaque_compiler_type_t type, std::function <bool (const CompilerType &integer_type, const ConstString &name, const llvm::APSInt &value)> const &callback) +{ + const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType(type)); + if (enum_type) + { + const clang::EnumDecl *enum_decl = enum_type->getDecl(); + if (enum_decl) + { + CompilerType integer_type(this, enum_decl->getIntegerType().getAsOpaquePtr()); + + clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; + for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos) + { + ConstString name(enum_pos->getNameAsString().c_str()); + if (!callback (integer_type, name, enum_pos->getInitVal())) + break; + } + } + } +} + + +#pragma mark Aggregate Types + +uint32_t +ClangASTContext::GetNumFields (lldb::opaque_compiler_type_t type) +{ + if (!type) + return 0; + + uint32_t count = 0; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::RecordType *record_type = llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr()); + if (record_type) + { + clang::RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) + { + uint32_t field_idx = 0; + clang::RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field) + ++field_idx; + count = field_idx; + } + } + } + break; + + case clang::Type::Typedef: + count = CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumFields(); + break; + + case clang::Type::Auto: + count = CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetNumFields(); + break; + + case clang::Type::Elaborated: + count = CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumFields(); + break; + + case clang::Type::Paren: + count = CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumFields(); + break; + + case clang::Type::ObjCObjectPointer: + if (GetCompleteType(type)) + { + const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType(); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl(); + + if (class_interface_decl) + count = class_interface_decl->ivar_size(); + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + count = class_interface_decl->ivar_size(); + } + } + break; + + default: + break; + } + return count; +} + +static lldb::opaque_compiler_type_t +GetObjCFieldAtIndex (clang::ASTContext *ast, + clang::ObjCInterfaceDecl *class_interface_decl, + size_t idx, + std::string& name, + uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, + bool *is_bitfield_ptr) +{ + if (class_interface_decl) + { + if (idx < (class_interface_decl->ivar_size())) + { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end(); + uint32_t ivar_idx = 0; + + for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++ivar_idx) + { + if (ivar_idx == idx) + { + const clang::ObjCIvarDecl* ivar_decl = *ivar_pos; + + clang::QualType ivar_qual_type(ivar_decl->getType()); + + name.assign(ivar_decl->getNameAsString()); + + if (bit_offset_ptr) + { + const clang::ASTRecordLayout &interface_layout = ast->getASTObjCInterfaceLayout(class_interface_decl); + *bit_offset_ptr = interface_layout.getFieldOffset (ivar_idx); + } + + const bool is_bitfield = ivar_pos->isBitField(); + + if (bitfield_bit_size_ptr) + { + *bitfield_bit_size_ptr = 0; + + if (is_bitfield && ast) + { + clang::Expr *bitfield_bit_size_expr = ivar_pos->getBitWidth(); + llvm::APSInt bitfield_apsint; + if (bitfield_bit_size_expr && bitfield_bit_size_expr->EvaluateAsInt(bitfield_apsint, *ast)) + { + *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue(); + } + } + } + if (is_bitfield_ptr) + *is_bitfield_ptr = is_bitfield; + + return ivar_qual_type.getAsOpaquePtr(); + } + } + } + } + return nullptr; +} + +CompilerType +ClangASTContext::GetFieldAtIndex (lldb::opaque_compiler_type_t type, size_t idx, + std::string& name, + uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, + bool *is_bitfield_ptr) +{ + if (!type) + return CompilerType(); + + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + uint32_t field_idx = 0; + clang::RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx) + { + if (idx == field_idx) + { + // Print the member type if requested + // Print the member name and equal sign + name.assign(field->getNameAsString()); + + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + if (bit_offset_ptr) + { + const clang::ASTRecordLayout &record_layout = getASTContext()->getASTRecordLayout(record_decl); + *bit_offset_ptr = record_layout.getFieldOffset (field_idx); + } + + const bool is_bitfield = field->isBitField(); + + if (bitfield_bit_size_ptr) + { + *bitfield_bit_size_ptr = 0; + + if (is_bitfield) + { + clang::Expr *bitfield_bit_size_expr = field->getBitWidth(); + llvm::APSInt bitfield_apsint; + if (bitfield_bit_size_expr && bitfield_bit_size_expr->EvaluateAsInt(bitfield_apsint, *getASTContext())) + { + *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue(); + } + } + } + if (is_bitfield_ptr) + *is_bitfield_ptr = is_bitfield; + + return CompilerType (getASTContext(), field->getType()); + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + if (GetCompleteType(type)) + { + const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType(); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl(); + return CompilerType (this, GetObjCFieldAtIndex(getASTContext(), class_interface_decl, idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr)); + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + return CompilerType (this, GetObjCFieldAtIndex(getASTContext(), class_interface_decl, idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr)); + } + } + break; + + + case clang::Type::Typedef: + return CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()). + GetFieldAtIndex (idx, + name, + bit_offset_ptr, + bitfield_bit_size_ptr, + is_bitfield_ptr); + + case clang::Type::Auto: + return CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()). + GetFieldAtIndex (idx, + name, + bit_offset_ptr, + bitfield_bit_size_ptr, + is_bitfield_ptr); + + case clang::Type::Elaborated: + return CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()). + GetFieldAtIndex (idx, + name, + bit_offset_ptr, + bitfield_bit_size_ptr, + is_bitfield_ptr); + + case clang::Type::Paren: + return CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()). + GetFieldAtIndex (idx, + name, + bit_offset_ptr, + bitfield_bit_size_ptr, + is_bitfield_ptr); + + default: + break; + } + return CompilerType(); +} + +uint32_t +ClangASTContext::GetNumDirectBaseClasses (lldb::opaque_compiler_type_t type) +{ + uint32_t count = 0; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + count = cxx_record_decl->getNumBases(); + } + break; + + case clang::Type::ObjCObjectPointer: + count = GetPointeeType(type).GetNumDirectBaseClasses(); + break; + + case clang::Type::ObjCObject: + if (GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType(); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl && class_interface_decl->getSuperClass()) + count = 1; + } + } + break; + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) + { + const clang::ObjCInterfaceType *objc_interface_type = qual_type->getAs<clang::ObjCInterfaceType>(); + if (objc_interface_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_interface_type->getInterface(); + + if (class_interface_decl && class_interface_decl->getSuperClass()) + count = 1; + } + } + break; + + + case clang::Type::Typedef: + count = GetNumDirectBaseClasses(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr()); + break; + + case clang::Type::Auto: + count = GetNumDirectBaseClasses(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr()); + break; + + case clang::Type::Elaborated: + count = GetNumDirectBaseClasses(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr()); + break; + + case clang::Type::Paren: + return GetNumDirectBaseClasses(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()); + + default: + break; + } + return count; + +} + +uint32_t +ClangASTContext::GetNumVirtualBaseClasses (lldb::opaque_compiler_type_t type) +{ + uint32_t count = 0; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + count = cxx_record_decl->getNumVBases(); + } + break; + + case clang::Type::Typedef: + count = GetNumVirtualBaseClasses(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr()); + break; + + case clang::Type::Auto: + count = GetNumVirtualBaseClasses(llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr()); + break; + + case clang::Type::Elaborated: + count = GetNumVirtualBaseClasses(llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr()); + break; + + case clang::Type::Paren: + count = GetNumVirtualBaseClasses(llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()); + break; + + default: + break; + } + return count; + +} + +CompilerType +ClangASTContext::GetDirectBaseClassAtIndex (lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) +{ + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + uint32_t curr_idx = 0; + clang::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, ++curr_idx) + { + if (curr_idx == idx) + { + if (bit_offset_ptr) + { + const clang::ASTRecordLayout &record_layout = getASTContext()->getASTRecordLayout(cxx_record_decl); + const clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + if (base_class->isVirtual()) + *bit_offset_ptr = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8; + else + *bit_offset_ptr = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8; + } + return CompilerType (this, base_class->getType().getAsOpaquePtr()); + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + return GetPointeeType(type).GetDirectBaseClassAtIndex(idx, bit_offset_ptr); + + case clang::Type::ObjCObject: + if (idx == 0 && GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType(); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + { + clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + if (superclass_interface_decl) + { + if (bit_offset_ptr) + *bit_offset_ptr = 0; + return CompilerType (getASTContext(), getASTContext()->getObjCInterfaceType(superclass_interface_decl)); + } + } + } + } + break; + case clang::Type::ObjCInterface: + if (idx == 0 && GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_interface_type = qual_type->getAs<clang::ObjCInterfaceType>(); + if (objc_interface_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_interface_type->getInterface(); + + if (class_interface_decl) + { + clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + if (superclass_interface_decl) + { + if (bit_offset_ptr) + *bit_offset_ptr = 0; + return CompilerType (getASTContext(), getASTContext()->getObjCInterfaceType(superclass_interface_decl)); + } + } + } + } + break; + + + case clang::Type::Typedef: + return GetDirectBaseClassAtIndex (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), idx, bit_offset_ptr); + + case clang::Type::Auto: + return GetDirectBaseClassAtIndex (llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), idx, bit_offset_ptr); + + case clang::Type::Elaborated: + return GetDirectBaseClassAtIndex (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), idx, bit_offset_ptr); + + case clang::Type::Paren: + return GetDirectBaseClassAtIndex (llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), idx, bit_offset_ptr); + + default: + break; + } + return CompilerType(); +} + +CompilerType +ClangASTContext::GetVirtualBaseClassAtIndex (lldb::opaque_compiler_type_t type, + size_t idx, + uint32_t *bit_offset_ptr) +{ + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { - if (clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx)) + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + uint32_t curr_idx = 0; + clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->vbases_begin(), base_class_end = cxx_record_decl->vbases_end(); + base_class != base_class_end; + ++base_class, ++curr_idx) + { + if (curr_idx == idx) + { + if (bit_offset_ptr) + { + const clang::ASTRecordLayout &record_layout = getASTContext()->getASTRecordLayout(cxx_record_decl); + const clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + *bit_offset_ptr = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8; + + } + return CompilerType (this, base_class->getType().getAsOpaquePtr()); + } + } + } + } + break; + + case clang::Type::Typedef: + return GetVirtualBaseClassAtIndex (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), idx, bit_offset_ptr); + + case clang::Type::Auto: + return GetVirtualBaseClassAtIndex (llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), idx, bit_offset_ptr); + + case clang::Type::Elaborated: + return GetVirtualBaseClassAtIndex (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), idx, bit_offset_ptr); + + case clang::Type::Paren: + return GetVirtualBaseClassAtIndex (llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), idx, bit_offset_ptr); + + default: + break; + } + return CompilerType(); + +} + +// If a pointer to a pointee type (the clang_type arg) says that it has no +// children, then we either need to trust it, or override it and return a +// different result. For example, an "int *" has one child that is an integer, +// but a function pointer doesn't have any children. Likewise if a Record type +// claims it has no children, then there really is nothing to show. +uint32_t +ClangASTContext::GetNumPointeeChildren (clang::QualType type) +{ + if (type.isNull()) + return 0; + + clang::QualType qual_type(type.getCanonicalType()); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) + { + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::Void: + case clang::BuiltinType::NullPtr: + case clang::BuiltinType::OCLEvent: + case clang::BuiltinType::OCLImage1d: + case clang::BuiltinType::OCLImage1dArray: + case clang::BuiltinType::OCLImage1dBuffer: + case clang::BuiltinType::OCLImage2d: + case clang::BuiltinType::OCLImage2dArray: + case clang::BuiltinType::OCLImage3d: + case clang::BuiltinType::OCLSampler: + return 0; + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + case clang::BuiltinType::Dependent: + case clang::BuiltinType::Overload: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCSel: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::Half: + case clang::BuiltinType::ARCUnbridgedCast: + case clang::BuiltinType::PseudoObject: + case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::OMPArraySection: + return 1; + default: + return 0; + } + break; + + case clang::Type::Complex: return 1; + case clang::Type::Pointer: return 1; + case clang::Type::BlockPointer: return 0; // If block pointers don't have debug info, then no children for them + case clang::Type::LValueReference: return 1; + case clang::Type::RValueReference: return 1; + case clang::Type::MemberPointer: return 0; + case clang::Type::ConstantArray: return 0; + case clang::Type::IncompleteArray: return 0; + case clang::Type::VariableArray: return 0; + case clang::Type::DependentSizedArray: return 0; + case clang::Type::DependentSizedExtVector: return 0; + case clang::Type::Vector: return 0; + case clang::Type::ExtVector: return 0; + case clang::Type::FunctionProto: return 0; // When we function pointers, they have no children... + case clang::Type::FunctionNoProto: return 0; // When we function pointers, they have no children... + case clang::Type::UnresolvedUsing: return 0; + case clang::Type::Paren: return GetNumPointeeChildren (llvm::cast<clang::ParenType>(qual_type)->desugar()); + case clang::Type::Typedef: return GetNumPointeeChildren (llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()); + case clang::Type::Auto: return GetNumPointeeChildren (llvm::cast<clang::AutoType>(qual_type)->getDeducedType()); + case clang::Type::Elaborated: return GetNumPointeeChildren (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()); + case clang::Type::TypeOfExpr: return 0; + case clang::Type::TypeOf: return 0; + case clang::Type::Decltype: return 0; + case clang::Type::Record: return 0; + case clang::Type::Enum: return 1; + case clang::Type::TemplateTypeParm: return 1; + case clang::Type::SubstTemplateTypeParm: return 1; + case clang::Type::TemplateSpecialization: return 1; + case clang::Type::InjectedClassName: return 0; + case clang::Type::DependentName: return 1; + case clang::Type::DependentTemplateSpecialization: return 1; + case clang::Type::ObjCObject: return 0; + case clang::Type::ObjCInterface: return 0; + case clang::Type::ObjCObjectPointer: return 1; + default: + break; + } + return 0; +} + + +CompilerType +ClangASTContext::GetChildCompilerTypeAtIndex (lldb::opaque_compiler_type_t type, + ExecutionContext *exe_ctx, + size_t idx, + bool transparent_pointers, + bool omit_empty_base_classes, + bool ignore_array_bounds, + 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, + bool &child_is_base_class, + bool &child_is_deref_of_parent, + ValueObject *valobj, + uint64_t &language_flags) +{ + if (!type) + return CompilerType(); + + clang::QualType parent_qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass parent_type_class = parent_qual_type->getTypeClass(); + child_bitfield_bit_size = 0; + child_bitfield_bit_offset = 0; + child_is_base_class = false; + language_flags = 0; + + const bool idx_is_valid = idx < GetNumChildren (type, omit_empty_base_classes); + uint32_t bit_offset; + switch (parent_type_class) + { + case clang::Type::Builtin: + if (idx_is_valid) + { + switch (llvm::cast<clang::BuiltinType>(parent_qual_type)->getKind()) + { + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + child_name = "isa"; + child_byte_size = getASTContext()->getTypeSize(getASTContext()->ObjCBuiltinClassTy) / CHAR_BIT; + return CompilerType (getASTContext(), getASTContext()->ObjCBuiltinClassTy); + + default: + break; + } + } + break; + + case clang::Type::Record: + if (idx_is_valid && GetCompleteType(type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(parent_qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::ASTRecordLayout &record_layout = getASTContext()->getASTRecordLayout(record_decl); + uint32_t child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + // We might have base classes to print out first + clang::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 clang::CXXRecordDecl *base_class_decl = nullptr; + + // Skip empty base classes + if (omit_empty_base_classes) + { + base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + if (ClangASTContext::RecordHasFields(base_class_decl) == false) + continue; + } + + if (idx == child_idx) + { + if (base_class_decl == nullptr) + base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + + + if (base_class->isVirtual()) + { + bool handled = false; + if (valobj) + { + Error err; + AddressType addr_type = eAddressTypeInvalid; + lldb::addr_t vtable_ptr_addr = valobj->GetCPPVTableAddress(addr_type); + + if (vtable_ptr_addr != LLDB_INVALID_ADDRESS && addr_type == eAddressTypeLoad) + { + + ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process) + { + clang::VTableContextBase *vtable_ctx = getASTContext()->getVTableContext(); + if (vtable_ctx) + { + if (vtable_ctx->isMicrosoft()) + { + clang::MicrosoftVTableContext *msoft_vtable_ctx = static_cast<clang::MicrosoftVTableContext *>(vtable_ctx); + + if (vtable_ptr_addr) + { + const lldb::addr_t vbtable_ptr_addr = vtable_ptr_addr + record_layout.getVBPtrOffset().getQuantity(); + + const lldb::addr_t vbtable_ptr = process->ReadPointerFromMemory(vbtable_ptr_addr, err); + if (vbtable_ptr != LLDB_INVALID_ADDRESS) + { + // Get the index into the virtual base table. The index is the index in uint32_t from vbtable_ptr + const unsigned vbtable_index = msoft_vtable_ctx->getVBTableIndex(cxx_record_decl, base_class_decl); + const lldb::addr_t base_offset_addr = vbtable_ptr + vbtable_index * 4; + const uint32_t base_offset = process->ReadUnsignedIntegerFromMemory(base_offset_addr, 4, UINT32_MAX, err); + if (base_offset != UINT32_MAX) + { + handled = true; + bit_offset = base_offset * 8; + } + } + } + } + else + { + clang::ItaniumVTableContext *itanium_vtable_ctx = static_cast<clang::ItaniumVTableContext *>(vtable_ctx); + if (vtable_ptr_addr) + { + const lldb::addr_t vtable_ptr = process->ReadPointerFromMemory(vtable_ptr_addr, err); + if (vtable_ptr != LLDB_INVALID_ADDRESS) + { + clang::CharUnits base_offset_offset = itanium_vtable_ctx->getVirtualBaseOffsetOffset(cxx_record_decl, base_class_decl); + const lldb::addr_t base_offset_addr = vtable_ptr + base_offset_offset.getQuantity(); + const uint32_t base_offset = process->ReadUnsignedIntegerFromMemory(base_offset_addr, 4, UINT32_MAX, err); + if (base_offset != UINT32_MAX) + { + handled = true; + bit_offset = base_offset * 8; + } + } + } + } + } + } + } + + } + if (!handled) + bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8; + } + else + bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8; + + // Base classes should be a multiple of 8 bits in size + child_byte_offset = bit_offset/8; + CompilerType base_class_clang_type(getASTContext(), base_class->getType()); + child_name = base_class_clang_type.GetTypeName().AsCString(""); + uint64_t base_class_clang_type_bit_size = base_class_clang_type.GetBitSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + + // Base classes bit sizes should be a multiple of 8 bits in size + assert (base_class_clang_type_bit_size % 8 == 0); + child_byte_size = base_class_clang_type_bit_size / 8; + child_is_base_class = true; + return base_class_clang_type; + } + // We don't increment the child index in the for loop since we might + // be skipping empty base classes + ++child_idx; + } + } + // Make sure index is in range... + uint32_t field_idx = 0; + clang::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. + CompilerType field_clang_type (getASTContext(), field->getType()); + assert(field_idx < record_layout.getFieldCount()); + child_byte_size = field_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + + // 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 (getASTContext(), *field, child_bitfield_bit_size)) + child_bitfield_bit_offset = bit_offset % 8; + + return field_clang_type; + } + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (idx_is_valid && GetCompleteType(type)) + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(parent_qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + uint32_t child_idx = 0; + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + { + + const clang::ASTRecordLayout &interface_layout = getASTContext()->getASTObjCInterfaceLayout(class_interface_decl); + clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + if (superclass_interface_decl) + { + if (omit_empty_base_classes) + { + CompilerType base_class_clang_type (getASTContext(), getASTContext()->getObjCInterfaceType(superclass_interface_decl)); + if (base_class_clang_type.GetNumChildren(omit_empty_base_classes) > 0) + { + if (idx == 0) + { + clang::QualType ivar_qual_type(getASTContext()->getObjCInterfaceType(superclass_interface_decl)); + + + child_name.assign(superclass_interface_decl->getNameAsString().c_str()); + + clang::TypeInfo ivar_type_info = getASTContext()->getTypeInfo(ivar_qual_type.getTypePtr()); + + child_byte_size = ivar_type_info.Width / 8; + child_byte_offset = 0; + child_is_base_class = true; + + return CompilerType (getASTContext(), ivar_qual_type); + } + + ++child_idx; + } + } + else + ++child_idx; + } + + const uint32_t superclass_idx = child_idx; + + if (idx < (child_idx + class_interface_decl->ivar_size())) + { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end(); + + for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos) + { + if (child_idx == idx) + { + clang::ObjCIvarDecl* ivar_decl = *ivar_pos; + + clang::QualType ivar_qual_type(ivar_decl->getType()); + + child_name.assign(ivar_decl->getNameAsString().c_str()); + + clang::TypeInfo ivar_type_info = getASTContext()->getTypeInfo(ivar_qual_type.getTypePtr()); + + child_byte_size = ivar_type_info.Width / 8; + + // Figure out the field offset within the current struct/union/class type + // For ObjC objects, we can't trust the bit offset we get from the Clang AST, since + // that doesn't account for the space taken up by unbacked properties, or from + // the changing size of base classes that are newer than this class. + // So if we have a process around that we can ask about this object, do so. + child_byte_offset = LLDB_INVALID_IVAR_OFFSET; + Process *process = nullptr; + if (exe_ctx) + process = exe_ctx->GetProcessPtr(); + if (process) + { + ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); + if (objc_runtime != nullptr) + { + CompilerType parent_ast_type (getASTContext(), parent_qual_type); + child_byte_offset = objc_runtime->GetByteOffsetForIvar (parent_ast_type, ivar_decl->getNameAsString().c_str()); + } + } + + // Setting this to UINT32_MAX to make sure we don't compute it twice... + bit_offset = UINT32_MAX; + + if (child_byte_offset == static_cast<int32_t>(LLDB_INVALID_IVAR_OFFSET)) + { + bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx); + child_byte_offset = bit_offset / 8; + } + + // Note, the ObjC Ivar Byte offset is just that, it doesn't account for the bit offset + // of a bitfield within its containing object. So regardless of where we get the byte + // offset from, we still need to get the bit offset for bitfields from the layout. + + if (ClangASTContext::FieldIsBitfield (getASTContext(), ivar_decl, child_bitfield_bit_size)) + { + if (bit_offset == UINT32_MAX) + bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx); + + child_bitfield_bit_offset = bit_offset % 8; + } + return CompilerType (getASTContext(), ivar_qual_type); + } + ++child_idx; + } + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + if (idx_is_valid) + { + CompilerType pointee_clang_type (GetPointeeType(type)); + + if (transparent_pointers && pointee_clang_type.IsAggregateType()) + { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return pointee_clang_type.GetChildCompilerTypeAtIndex (exe_ctx, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + tmp_child_is_deref_of_parent, + valobj, + language_flags); + } + else + { + child_is_deref_of_parent = true; + const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL; + if (parent_name) + { + child_name.assign(1, '*'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0 && pointee_clang_type.GetCompleteType()) + { + child_byte_size = pointee_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + child_byte_offset = 0; + return pointee_clang_type; + } + } + } + break; + + case clang::Type::Vector: + case clang::Type::ExtVector: + if (idx_is_valid) + { + const clang::VectorType *array = llvm::cast<clang::VectorType>(parent_qual_type.getTypePtr()); + if (array) + { + CompilerType element_type (getASTContext(), array->getElementType()); + if (element_type.GetCompleteType()) + { + char element_name[64]; + ::snprintf (element_name, sizeof (element_name), "[%" PRIu64 "]", static_cast<uint64_t>(idx)); + child_name.assign(element_name); + child_byte_size = element_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; + return element_type; + } + } + } + break; + + case clang::Type::ConstantArray: + case clang::Type::IncompleteArray: + if (ignore_array_bounds || idx_is_valid) + { + const clang::ArrayType *array = GetQualType(type)->getAsArrayTypeUnsafe(); + if (array) + { + CompilerType element_type (getASTContext(), array->getElementType()); + if (element_type.GetCompleteType()) + { + char element_name[64]; + ::snprintf (element_name, sizeof (element_name), "[%" PRIu64 "]", static_cast<uint64_t>(idx)); + child_name.assign(element_name); + child_byte_size = element_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; + return element_type; + } + } + } + break; + + + case clang::Type::Pointer: + if (idx_is_valid) + { + CompilerType pointee_clang_type (GetPointeeType(type)); + + // Don't dereference "void *" pointers + if (pointee_clang_type.IsVoidType()) + return CompilerType(); + + if (transparent_pointers && pointee_clang_type.IsAggregateType ()) + { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return pointee_clang_type.GetChildCompilerTypeAtIndex (exe_ctx, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + tmp_child_is_deref_of_parent, + valobj, + language_flags); + } + else + { + child_is_deref_of_parent = true; + + const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL; + if (parent_name) + { + child_name.assign(1, '*'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0) + { + child_byte_size = pointee_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + child_byte_offset = 0; + return pointee_clang_type; + } + } + } + break; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + if (idx_is_valid) + { + const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(parent_qual_type.getTypePtr()); + CompilerType pointee_clang_type (getASTContext(), reference_type->getPointeeType()); + if (transparent_pointers && pointee_clang_type.IsAggregateType ()) + { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return pointee_clang_type.GetChildCompilerTypeAtIndex (exe_ctx, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + tmp_child_is_deref_of_parent, + valobj, + language_flags); + } + else + { + const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL; + if (parent_name) + { + child_name.assign(1, '&'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0) + { + child_byte_size = pointee_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); + child_byte_offset = 0; + return pointee_clang_type; + } + } + } + break; + + case clang::Type::Typedef: + { + CompilerType typedefed_clang_type (getASTContext(), llvm::cast<clang::TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType()); + return typedefed_clang_type.GetChildCompilerTypeAtIndex (exe_ctx, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent, + valobj, + language_flags); + } + break; + + case clang::Type::Auto: + { + CompilerType elaborated_clang_type (getASTContext(), llvm::cast<clang::AutoType>(parent_qual_type)->getDeducedType()); + return elaborated_clang_type.GetChildCompilerTypeAtIndex (exe_ctx, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent, + valobj, + language_flags); + } + + case clang::Type::Elaborated: { - if (method_decl->isStatic()) + CompilerType elaborated_clang_type (getASTContext(), llvm::cast<clang::ElaboratedType>(parent_qual_type)->getNamedType()); + return elaborated_clang_type.GetChildCompilerTypeAtIndex (exe_ctx, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent, + valobj, + language_flags); + } + + case clang::Type::Paren: + { + CompilerType paren_clang_type (getASTContext(), llvm::cast<clang::ParenType>(parent_qual_type)->desugar()); + return paren_clang_type.GetChildCompilerTypeAtIndex (exe_ctx, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent, + valobj, + language_flags); + } + + + default: + break; + } + return CompilerType(); +} + +static uint32_t +GetIndexForRecordBase +( + const clang::RecordDecl *record_decl, + const clang::CXXBaseSpecifier *base_spec, + bool omit_empty_base_classes + ) +{ + uint32_t child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + + // const char *super_name = record_decl->getNameAsCString(); + // const char *base_name = base_spec->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString(); + // printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name); + // + if (cxx_record_decl) + { + clang::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) { - is_instance_method = false; + if (BaseSpecifierIsEmpty (base_class)) + continue; } + + // printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n", super_name, base_name, + // child_idx, + // base_class->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString()); + // + // + if (base_class == base_spec) + return child_idx; + ++child_idx; + } + } + + return UINT32_MAX; +} + + +static uint32_t +GetIndexForRecordChild (const clang::RecordDecl *record_decl, + clang::NamedDecl *canonical_decl, + bool omit_empty_base_classes) +{ + uint32_t child_idx = ClangASTContext::GetNumBaseClasses (llvm::dyn_cast<clang::CXXRecordDecl>(record_decl), + omit_empty_base_classes); + + clang::RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { + 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 (lldb::opaque_compiler_type_t type, const char *name, + bool omit_empty_base_classes, + std::vector<uint32_t>& child_indexes) +{ + if (type && name && name[0]) + { + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + + assert(record_decl); + uint32_t child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + + // Try and find a field that matches NAME + clang::RecordDecl::field_iterator field, field_end; + llvm::StringRef name_sref(name); + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { + llvm::StringRef field_name = field->getName(); + if (field_name.empty()) + { + CompilerType field_type(getASTContext(),field->getType()); + child_indexes.push_back(child_idx); + if (field_type.GetIndexOfChildMemberWithName(name, omit_empty_base_classes, child_indexes)) + return child_indexes.size(); + child_indexes.pop_back(); + + } + else if (field_name.equals (name_sref)) + { + // We have to add on the number of base classes to this index! + child_indexes.push_back (child_idx + ClangASTContext::GetNumBaseClasses (cxx_record_decl, omit_empty_base_classes)); + return child_indexes.size(); + } + } + + if (cxx_record_decl) + { + const clang::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... + clang::IdentifierInfo & ident_ref = getASTContext()->Idents.get(name_sref); + clang::DeclarationName decl_name(&ident_ref); + + clang::CXXBasePaths paths; + if (cxx_record_decl->lookupInBases([decl_name](const clang::CXXBaseSpecifier *specifier, clang::CXXBasePath &path) { + return clang::CXXRecordDecl::FindOrdinaryMember(specifier, path, decl_name); + }, + paths)) + { + clang::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) + { + clang::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 = llvm::cast<clang::RecordDecl>(elem.Base->getType()->getAs<clang::RecordType>()->getDecl()); + } + } + for (clang::NamedDecl *path_decl : path->Decls) + { + child_idx = GetIndexForRecordChild (parent_record_decl, path_decl, 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 clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) + { + llvm::StringRef name_sref(name); + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + uint32_t child_idx = 0; + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end(); + clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + + for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++child_idx) + { + const clang::ObjCIvarDecl* ivar_decl = *ivar_pos; + + if (ivar_decl->getName().equals (name_sref)) + { + if ((!omit_empty_base_classes && superclass_interface_decl) || + ( omit_empty_base_classes && ObjCDeclHasIVars (superclass_interface_decl, true))) + ++child_idx; + + child_indexes.push_back (child_idx); + return child_indexes.size(); + } + } + + if (superclass_interface_decl) + { + // The super class index is always zero for ObjC classes, + // so we push it onto the child indexes in case we find + // an ivar in our superclass... + child_indexes.push_back (0); + + CompilerType superclass_clang_type (getASTContext(), getASTContext()->getObjCInterfaceType(superclass_interface_decl)); + if (superclass_clang_type.GetIndexOfChildMemberWithName (name, + omit_empty_base_classes, + child_indexes)) + { + // We did find an ivar in a superclass so just + // return the results! + return child_indexes.size(); + } + + // We didn't find an ivar matching "name" in our + // superclass, pop the superclass zero index that + // we pushed on above. + child_indexes.pop_back(); + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + { + CompilerType objc_object_clang_type (getASTContext(), llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType()); + return objc_object_clang_type.GetIndexOfChildMemberWithName (name, + omit_empty_base_classes, + child_indexes); + } + break; + + + case clang::Type::ConstantArray: + { + // const clang::ConstantArrayType *array = llvm::cast<clang::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->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 clang::Type::MemberPointerType: + // { + // MemberPointerType *mem_ptr_type = llvm::cast<MemberPointerType>(qual_type.getTypePtr()); + // clang::QualType pointee_type = mem_ptr_type->getPointeeType(); + // + // if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + // { + // return GetIndexOfChildWithName (ast, + // mem_ptr_type->getPointeeType().getAsOpaquePtr(), + // name); + // } + // } + // break; + // + case clang::Type::LValueReference: + case clang::Type::RValueReference: + { + const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + clang::QualType pointee_type(reference_type->getPointeeType()); + CompilerType pointee_clang_type (getASTContext(), pointee_type); + + if (pointee_clang_type.IsAggregateType ()) + { + return pointee_clang_type.GetIndexOfChildMemberWithName (name, + omit_empty_base_classes, + child_indexes); + } + } + break; + + case clang::Type::Pointer: + { + CompilerType pointee_clang_type (GetPointeeType(type)); + + if (pointee_clang_type.IsAggregateType ()) + { + return pointee_clang_type.GetIndexOfChildMemberWithName (name, + omit_empty_base_classes, + child_indexes); + } + } + break; + + case clang::Type::Typedef: + return CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildMemberWithName (name, + omit_empty_base_classes, + child_indexes); + + case clang::Type::Auto: + return CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetIndexOfChildMemberWithName (name, + omit_empty_base_classes, + child_indexes); + + case clang::Type::Elaborated: + return CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildMemberWithName (name, + omit_empty_base_classes, + child_indexes); + + case clang::Type::Paren: + return CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildMemberWithName (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 (lldb::opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes) +{ + if (type && name && name[0]) + { + clang::QualType qual_type(GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + + assert(record_decl); + uint32_t child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + + if (cxx_record_decl) + { + clang::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 + clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + if (omit_empty_base_classes && ClangASTContext::RecordHasFields(base_class_decl) == false) + continue; + + CompilerType base_class_clang_type (getASTContext(), base_class->getType()); + std::string base_class_type_name (base_class_clang_type.GetTypeName().AsCString("")); + if (base_class_type_name.compare (name) == 0) + return child_idx; + ++child_idx; + } + } + + // Try and find a field that matches NAME + clang::RecordDecl::field_iterator field, field_end; + llvm::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 clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) + { + llvm::StringRef name_sref(name); + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + uint32_t child_idx = 0; + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end(); + clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + + for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++child_idx) + { + const clang::ObjCIvarDecl* ivar_decl = *ivar_pos; + + if (ivar_decl->getName().equals (name_sref)) + { + if ((!omit_empty_base_classes && superclass_interface_decl) || + ( omit_empty_base_classes && ObjCDeclHasIVars (superclass_interface_decl, true))) + ++child_idx; + + return child_idx; + } + } + + if (superclass_interface_decl) + { + if (superclass_interface_decl->getName().equals (name_sref)) + return 0; + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + { + CompilerType pointee_clang_type (getASTContext(), llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType()); + return pointee_clang_type.GetIndexOfChildWithName (name, omit_empty_base_classes); + } + break; + + case clang::Type::ConstantArray: + { + // const clang::ConstantArrayType *array = llvm::cast<clang::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->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 clang::Type::MemberPointerType: + // { + // MemberPointerType *mem_ptr_type = llvm::cast<MemberPointerType>(qual_type.getTypePtr()); + // clang::QualType pointee_type = mem_ptr_type->getPointeeType(); + // + // if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + // { + // return GetIndexOfChildWithName (ast, + // mem_ptr_type->getPointeeType().getAsOpaquePtr(), + // name); + // } + // } + // break; + // + case clang::Type::LValueReference: + case clang::Type::RValueReference: + { + const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + CompilerType pointee_type (getASTContext(), reference_type->getPointeeType()); + + if (pointee_type.IsAggregateType ()) + { + return pointee_type.GetIndexOfChildWithName (name, omit_empty_base_classes); + } + } + break; + + case clang::Type::Pointer: + { + const clang::PointerType *pointer_type = llvm::cast<clang::PointerType>(qual_type.getTypePtr()); + CompilerType pointee_type (getASTContext(), pointer_type->getPointeeType()); + + if (pointee_type.IsAggregateType ()) + { + return pointee_type.GetIndexOfChildWithName (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->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 clang::Type::Auto: + return CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).GetIndexOfChildWithName (name, omit_empty_base_classes); + + case clang::Type::Elaborated: + return CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildWithName (name, omit_empty_base_classes); + + case clang::Type::Paren: + return CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildWithName (name, omit_empty_base_classes); + + case clang::Type::Typedef: + return CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildWithName (name, omit_empty_base_classes); + + default: + break; + } + } + return UINT32_MAX; +} + + +size_t +ClangASTContext::GetNumTemplateArguments (lldb::opaque_compiler_type_t type) +{ + if (!type) + return 0; + + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + const clang::ClassTemplateSpecializationDecl *template_decl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl); + if (template_decl) + return template_decl->getTemplateArgs().size(); + } + } + break; + + case clang::Type::Typedef: + return (CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType())).GetNumTemplateArguments(); + + case clang::Type::Auto: + return (CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType())).GetNumTemplateArguments(); + + case clang::Type::Elaborated: + return (CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType())).GetNumTemplateArguments(); + + case clang::Type::Paren: + return (CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar())).GetNumTemplateArguments(); + + default: + break; + } + + return 0; +} + +CompilerType +ClangASTContext::GetTemplateArgument (lldb::opaque_compiler_type_t type, size_t arg_idx, lldb::TemplateArgumentKind &kind) +{ + if (!type) + return CompilerType(); + + clang::QualType qual_type (GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + const clang::ClassTemplateSpecializationDecl *template_decl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl); + if (template_decl && arg_idx < template_decl->getTemplateArgs().size()) + { + const clang::TemplateArgument &template_arg = template_decl->getTemplateArgs()[arg_idx]; + switch (template_arg.getKind()) + { + case clang::TemplateArgument::Null: + kind = eTemplateArgumentKindNull; + return CompilerType(); + + case clang::TemplateArgument::Type: + kind = eTemplateArgumentKindType; + return CompilerType(getASTContext(), template_arg.getAsType()); + + case clang::TemplateArgument::Declaration: + kind = eTemplateArgumentKindDeclaration; + return CompilerType(); + + case clang::TemplateArgument::Integral: + kind = eTemplateArgumentKindIntegral; + return CompilerType(getASTContext(), template_arg.getIntegralType()); + + case clang::TemplateArgument::Template: + kind = eTemplateArgumentKindTemplate; + return CompilerType(); + + case clang::TemplateArgument::TemplateExpansion: + kind = eTemplateArgumentKindTemplateExpansion; + return CompilerType(); + + case clang::TemplateArgument::Expression: + kind = eTemplateArgumentKindExpression; + return CompilerType(); + + case clang::TemplateArgument::Pack: + kind = eTemplateArgumentKindPack; + return CompilerType(); + + default: + assert (!"Unhandled clang::TemplateArgument::ArgKind"); + break; + } + } + } + } + break; + + case clang::Type::Typedef: + return (CompilerType (getASTContext(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType())).GetTemplateArgument(arg_idx, kind); + + case clang::Type::Auto: + return (CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType())).GetTemplateArgument(arg_idx, kind); + + case clang::Type::Elaborated: + return (CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType())).GetTemplateArgument(arg_idx, kind); + + case clang::Type::Paren: + return (CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar())).GetTemplateArgument(arg_idx, kind); + + default: + break; + } + kind = eTemplateArgumentKindNull; + return CompilerType (); +} + +CompilerType +ClangASTContext::GetTypeForFormatters (void* type) +{ + if (type) + return RemoveFastQualifiers(CompilerType(this, type)); + return CompilerType(); +} + +static bool +IsOperator (const char *name, clang::OverloadedOperatorKind &op_kind) +{ + if (name == nullptr || name[0] == '\0') + return false; + +#define OPERATOR_PREFIX "operator" +#define OPERATOR_PREFIX_LENGTH (sizeof (OPERATOR_PREFIX) - 1) + + const char *post_op_name = nullptr; + + bool no_space = true; + + if (::strncmp(name, OPERATOR_PREFIX, OPERATOR_PREFIX_LENGTH)) + return false; + + post_op_name = name + OPERATOR_PREFIX_LENGTH; + + if (post_op_name[0] == ' ') + { + post_op_name++; + no_space = false; + } + +#undef OPERATOR_PREFIX +#undef OPERATOR_PREFIX_LENGTH + + // This is an operator, set the overloaded operator kind to invalid + // in case this is a conversion operator... + op_kind = clang::NUM_OVERLOADED_OPERATORS; + + switch (post_op_name[0]) + { + default: + if (no_space) + return false; + break; + case 'n': + if (no_space) + return false; + if (strcmp (post_op_name, "new") == 0) + op_kind = clang::OO_New; + else if (strcmp (post_op_name, "new[]") == 0) + op_kind = clang::OO_Array_New; + break; + + case 'd': + if (no_space) + return false; + if (strcmp (post_op_name, "delete") == 0) + op_kind = clang::OO_Delete; + else if (strcmp (post_op_name, "delete[]") == 0) + op_kind = clang::OO_Array_Delete; + break; + + case '+': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Plus; + else if (post_op_name[2] == '\0') + { + if (post_op_name[1] == '=') + op_kind = clang::OO_PlusEqual; + else if (post_op_name[1] == '+') + op_kind = clang::OO_PlusPlus; + } + break; + + case '-': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Minus; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '=': op_kind = clang::OO_MinusEqual; break; + case '-': op_kind = clang::OO_MinusMinus; break; + case '>': op_kind = clang::OO_Arrow; break; + } + } + else if (post_op_name[3] == '\0') + { + if (post_op_name[2] == '*') + op_kind = clang::OO_ArrowStar; break; + } + break; + + case '*': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Star; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_StarEqual; + break; + + case '/': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Slash; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_SlashEqual; + break; + + case '%': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Percent; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_PercentEqual; + break; + + + case '^': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Caret; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_CaretEqual; + break; + + case '&': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Amp; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '=': op_kind = clang::OO_AmpEqual; break; + case '&': op_kind = clang::OO_AmpAmp; break; + } + } + break; + + case '|': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Pipe; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '=': op_kind = clang::OO_PipeEqual; break; + case '|': op_kind = clang::OO_PipePipe; break; + } + } + break; + + case '~': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Tilde; + break; + + case '!': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Exclaim; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_ExclaimEqual; + break; + + case '=': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Equal; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_EqualEqual; + break; + + case '<': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Less; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '<': op_kind = clang::OO_LessLess; break; + case '=': op_kind = clang::OO_LessEqual; break; + } + } + else if (post_op_name[3] == '\0') + { + if (post_op_name[2] == '=') + op_kind = clang::OO_LessLessEqual; + } + break; + + case '>': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Greater; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '>': op_kind = clang::OO_GreaterGreater; break; + case '=': op_kind = clang::OO_GreaterEqual; break; + } + } + else if (post_op_name[1] == '>' && + post_op_name[2] == '=' && + post_op_name[3] == '\0') + { + op_kind = clang::OO_GreaterGreaterEqual; + } + break; + + case ',': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Comma; + break; + + case '(': + if (post_op_name[1] == ')' && post_op_name[2] == '\0') + op_kind = clang::OO_Call; + break; + + case '[': + if (post_op_name[1] == ']' && post_op_name[2] == '\0') + op_kind = clang::OO_Subscript; + break; + } + + return true; +} + +clang::EnumDecl * +ClangASTContext::GetAsEnumDecl (const CompilerType& type) +{ + const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType(type)); + if (enutype) + return enutype->getDecl(); + return NULL; +} + +clang::RecordDecl * +ClangASTContext::GetAsRecordDecl (const CompilerType& type) +{ + const clang::RecordType *record_type = llvm::dyn_cast<clang::RecordType>(GetCanonicalQualType(type)); + if (record_type) + return record_type->getDecl(); + return nullptr; +} + +clang::TagDecl * +ClangASTContext::GetAsTagDecl (const CompilerType& type) +{ + clang::QualType qual_type = GetCanonicalQualType(type); + if (qual_type.isNull()) + return nullptr; + else + return qual_type->getAsTagDecl(); +} + +clang::CXXRecordDecl * +ClangASTContext::GetAsCXXRecordDecl (lldb::opaque_compiler_type_t type) +{ + return GetCanonicalQualType(type)->getAsCXXRecordDecl(); +} + +clang::ObjCInterfaceDecl * +ClangASTContext::GetAsObjCInterfaceDecl (const CompilerType& type) +{ + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(GetCanonicalQualType(type)); + if (objc_class_type) + return objc_class_type->getInterface(); + return nullptr; +} + +clang::FieldDecl * +ClangASTContext::AddFieldToRecordType (const CompilerType& type, const char *name, + const CompilerType &field_clang_type, + AccessType access, + uint32_t bitfield_bit_size) +{ + if (!type.IsValid() || !field_clang_type.IsValid()) + return nullptr; + ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(type.GetTypeSystem()); + if (!ast) + return nullptr; + clang::ASTContext* clang_ast = ast->getASTContext(); + + clang::FieldDecl *field = nullptr; + + clang::Expr *bit_width = nullptr; + if (bitfield_bit_size != 0) + { + llvm::APInt bitfield_bit_size_apint(clang_ast->getTypeSize(clang_ast->IntTy), bitfield_bit_size); + bit_width = new (*clang_ast)clang::IntegerLiteral (*clang_ast, bitfield_bit_size_apint, clang_ast->IntTy, clang::SourceLocation()); + } + + clang::RecordDecl *record_decl = ast->GetAsRecordDecl (type); + if (record_decl) + { + field = clang::FieldDecl::Create (*clang_ast, + record_decl, + clang::SourceLocation(), + clang::SourceLocation(), + name ? &clang_ast->Idents.get(name) : nullptr, // Identifier + GetQualType(field_clang_type), // Field type + nullptr, // TInfo * + bit_width, // BitWidth + false, // Mutable + clang::ICIS_NoInit); // HasInit + + if (!name) + { + // Determine whether this field corresponds to an anonymous + // struct or union. + if (const clang::TagType *TagT = field->getType()->getAs<clang::TagType>()) { + if (clang::RecordDecl *Rec = llvm::dyn_cast<clang::RecordDecl>(TagT->getDecl())) + if (!Rec->getDeclName()) { + Rec->setAnonymousStructOrUnion(true); + field->setImplicit(); + + } + } + } + + if (field) + { + field->setAccess (ClangASTContext::ConvertAccessTypeToAccessSpecifier (access)); + + record_decl->addDecl(field); + +#ifdef LLDB_CONFIGURATION_DEBUG + VerifyDecl(field); +#endif + } + } + else + { + clang::ObjCInterfaceDecl *class_interface_decl = ast->GetAsObjCInterfaceDecl (type); + + if (class_interface_decl) + { + const bool is_synthesized = false; + + field_clang_type.GetCompleteType(); + + field = clang::ObjCIvarDecl::Create (*clang_ast, + class_interface_decl, + clang::SourceLocation(), + clang::SourceLocation(), + name ? &clang_ast->Idents.get(name) : nullptr, // Identifier + GetQualType(field_clang_type), // Field type + nullptr, // TypeSourceInfo * + ConvertAccessTypeToObjCIvarAccessControl (access), + bit_width, + is_synthesized); + + if (field) + { + class_interface_decl->addDecl(field); + +#ifdef LLDB_CONFIGURATION_DEBUG + VerifyDecl(field); +#endif + } + } + } + return field; +} + +void +ClangASTContext::BuildIndirectFields (const CompilerType& type) +{ + if (!type) + return; + + ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (!ast) + return; + + clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type); + + if (!record_decl) + return; + + typedef llvm::SmallVector <clang::IndirectFieldDecl *, 1> IndirectFieldVector; + + IndirectFieldVector indirect_fields; + clang::RecordDecl::field_iterator field_pos; + clang::RecordDecl::field_iterator field_end_pos = record_decl->field_end(); + clang::RecordDecl::field_iterator last_field_pos = field_end_pos; + for (field_pos = record_decl->field_begin(); field_pos != field_end_pos; last_field_pos = field_pos++) + { + if (field_pos->isAnonymousStructOrUnion()) + { + clang::QualType field_qual_type = field_pos->getType(); + + const clang::RecordType *field_record_type = field_qual_type->getAs<clang::RecordType>(); + + if (!field_record_type) + continue; + + clang::RecordDecl *field_record_decl = field_record_type->getDecl(); + + if (!field_record_decl) + continue; + + for (clang::RecordDecl::decl_iterator di = field_record_decl->decls_begin(), de = field_record_decl->decls_end(); + di != de; + ++di) + { + if (clang::FieldDecl *nested_field_decl = llvm::dyn_cast<clang::FieldDecl>(*di)) + { + clang::NamedDecl **chain = new (*ast->getASTContext()) clang::NamedDecl*[2]; + chain[0] = *field_pos; + chain[1] = nested_field_decl; + clang::IndirectFieldDecl *indirect_field = clang::IndirectFieldDecl::Create(*ast->getASTContext(), + record_decl, + clang::SourceLocation(), + nested_field_decl->getIdentifier(), + nested_field_decl->getType(), + chain, + 2); + + indirect_field->setImplicit(); + + indirect_field->setAccess(ClangASTContext::UnifyAccessSpecifiers(field_pos->getAccess(), + nested_field_decl->getAccess())); + + indirect_fields.push_back(indirect_field); + } + else if (clang::IndirectFieldDecl *nested_indirect_field_decl = llvm::dyn_cast<clang::IndirectFieldDecl>(*di)) + { + int nested_chain_size = nested_indirect_field_decl->getChainingSize(); + clang::NamedDecl **chain = new (*ast->getASTContext()) clang::NamedDecl*[nested_chain_size + 1]; + chain[0] = *field_pos; + + int chain_index = 1; + for (clang::IndirectFieldDecl::chain_iterator nci = nested_indirect_field_decl->chain_begin(), + nce = nested_indirect_field_decl->chain_end(); + nci < nce; + ++nci) + { + chain[chain_index] = *nci; + chain_index++; + } + + clang::IndirectFieldDecl *indirect_field = clang::IndirectFieldDecl::Create(*ast->getASTContext(), + record_decl, + clang::SourceLocation(), + nested_indirect_field_decl->getIdentifier(), + nested_indirect_field_decl->getType(), + chain, + nested_chain_size + 1); + + indirect_field->setImplicit(); + + indirect_field->setAccess(ClangASTContext::UnifyAccessSpecifiers(field_pos->getAccess(), + nested_indirect_field_decl->getAccess())); + + indirect_fields.push_back(indirect_field); + } + } + } + } + + // Check the last field to see if it has an incomplete array type as its + // last member and if it does, the tell the record decl about it + if (last_field_pos != field_end_pos) + { + if (last_field_pos->getType()->isIncompleteArrayType()) + record_decl->hasFlexibleArrayMember(); + } + + for (IndirectFieldVector::iterator ifi = indirect_fields.begin(), ife = indirect_fields.end(); + ifi < ife; + ++ifi) + { + record_decl->addDecl(*ifi); + } +} + +void +ClangASTContext::SetIsPacked (const CompilerType& type) +{ + if (type) + { + ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (ast) + { + clang::RecordDecl *record_decl = GetAsRecordDecl(type); + + if (!record_decl) + return; + + record_decl->addAttr(clang::PackedAttr::CreateImplicit(*ast->getASTContext())); + } + } +} + +clang::VarDecl * +ClangASTContext::AddVariableToRecordType (const CompilerType& type, const char *name, + const CompilerType &var_type, + AccessType access) +{ + clang::VarDecl *var_decl = nullptr; + + if (!type.IsValid() || !var_type.IsValid()) + return nullptr; + ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (!ast) + return nullptr; + + clang::RecordDecl *record_decl = ast->GetAsRecordDecl (type); + if (record_decl) + { + var_decl = clang::VarDecl::Create (*ast->getASTContext(), // ASTContext & + record_decl, // DeclContext * + clang::SourceLocation(), // clang::SourceLocation StartLoc + clang::SourceLocation(), // clang::SourceLocation IdLoc + name ? &ast->getASTContext()->Idents.get(name) : nullptr, // clang::IdentifierInfo * + GetQualType(var_type), // Variable clang::QualType + nullptr, // TypeSourceInfo * + clang::SC_Static); // StorageClass + if (var_decl) + { + var_decl->setAccess(ClangASTContext::ConvertAccessTypeToAccessSpecifier (access)); + record_decl->addDecl(var_decl); + +#ifdef LLDB_CONFIGURATION_DEBUG + VerifyDecl(var_decl); +#endif + } + } + return var_decl; +} + + +clang::CXXMethodDecl * +ClangASTContext::AddMethodToCXXRecordType (lldb::opaque_compiler_type_t type, const char *name, + const CompilerType &method_clang_type, + lldb::AccessType access, + bool is_virtual, + bool is_static, + bool is_inline, + bool is_explicit, + bool is_attr_used, + bool is_artificial) +{ + if (!type || !method_clang_type.IsValid() || name == nullptr || name[0] == '\0') + return nullptr; + + clang::QualType record_qual_type(GetCanonicalQualType(type)); + + clang::CXXRecordDecl *cxx_record_decl = record_qual_type->getAsCXXRecordDecl(); + + if (cxx_record_decl == nullptr) + return nullptr; + + clang::QualType method_qual_type (GetQualType(method_clang_type)); + + clang::CXXMethodDecl *cxx_method_decl = nullptr; + + clang::DeclarationName decl_name (&getASTContext()->Idents.get(name)); + + const clang::FunctionType *function_type = llvm::dyn_cast<clang::FunctionType>(method_qual_type.getTypePtr()); + + if (function_type == nullptr) + return nullptr; + + const clang::FunctionProtoType *method_function_prototype (llvm::dyn_cast<clang::FunctionProtoType>(function_type)); + + if (!method_function_prototype) + return nullptr; + + unsigned int num_params = method_function_prototype->getNumParams(); + + clang::CXXDestructorDecl *cxx_dtor_decl(nullptr); + clang::CXXConstructorDecl *cxx_ctor_decl(nullptr); + + if (is_artificial) + return nullptr; // skip everything artificial + + if (name[0] == '~') + { + cxx_dtor_decl = clang::CXXDestructorDecl::Create (*getASTContext(), + cxx_record_decl, + clang::SourceLocation(), + clang::DeclarationNameInfo (getASTContext()->DeclarationNames.getCXXDestructorName (getASTContext()->getCanonicalType (record_qual_type)), clang::SourceLocation()), + method_qual_type, + nullptr, + is_inline, + is_artificial); + cxx_method_decl = cxx_dtor_decl; + } + else if (decl_name == cxx_record_decl->getDeclName()) + { + cxx_ctor_decl = clang::CXXConstructorDecl::Create (*getASTContext(), + cxx_record_decl, + clang::SourceLocation(), + clang::DeclarationNameInfo (getASTContext()->DeclarationNames.getCXXConstructorName (getASTContext()->getCanonicalType (record_qual_type)), clang::SourceLocation()), + method_qual_type, + nullptr, // TypeSourceInfo * + is_explicit, + is_inline, + is_artificial, + false /*is_constexpr*/); + cxx_method_decl = cxx_ctor_decl; + } + else + { + clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None; + clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; + + if (IsOperator (name, op_kind)) + { + if (op_kind != clang::NUM_OVERLOADED_OPERATORS) + { + // Check the number of operator parameters. Sometimes we have + // seen bad DWARF that doesn't correctly describe operators and + // if we try to create a method and add it to the class, clang + // will assert and crash, so we need to make sure things are + // acceptable. + if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount (op_kind, num_params)) + return nullptr; + cxx_method_decl = clang::CXXMethodDecl::Create (*getASTContext(), + cxx_record_decl, + clang::SourceLocation(), + clang::DeclarationNameInfo (getASTContext()->DeclarationNames.getCXXOperatorName (op_kind), clang::SourceLocation()), + method_qual_type, + nullptr, // TypeSourceInfo * + SC, + is_inline, + false /*is_constexpr*/, + clang::SourceLocation()); + } + else if (num_params == 0) + { + // Conversion operators don't take params... + cxx_method_decl = clang::CXXConversionDecl::Create (*getASTContext(), + cxx_record_decl, + clang::SourceLocation(), + clang::DeclarationNameInfo (getASTContext()->DeclarationNames.getCXXConversionFunctionName (getASTContext()->getCanonicalType (function_type->getReturnType())), clang::SourceLocation()), + method_qual_type, + nullptr, // TypeSourceInfo * + is_inline, + is_explicit, + false /*is_constexpr*/, + clang::SourceLocation()); + } + } + + if (cxx_method_decl == nullptr) + { + cxx_method_decl = clang::CXXMethodDecl::Create (*getASTContext(), + cxx_record_decl, + clang::SourceLocation(), + clang::DeclarationNameInfo (decl_name, clang::SourceLocation()), + method_qual_type, + nullptr, // TypeSourceInfo * + SC, + is_inline, + false /*is_constexpr*/, + clang::SourceLocation()); + } + } + + clang::AccessSpecifier access_specifier = ClangASTContext::ConvertAccessTypeToAccessSpecifier (access); + + cxx_method_decl->setAccess (access_specifier); + cxx_method_decl->setVirtualAsWritten (is_virtual); + + if (is_attr_used) + cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(*getASTContext())); + + // Populate the method decl with parameter decls + + llvm::SmallVector<clang::ParmVarDecl *, 12> params; + + for (unsigned param_index = 0; + param_index < num_params; + ++param_index) + { + params.push_back (clang::ParmVarDecl::Create (*getASTContext(), + cxx_method_decl, + clang::SourceLocation(), + clang::SourceLocation(), + nullptr, // anonymous + method_function_prototype->getParamType(param_index), + nullptr, + clang::SC_None, + nullptr)); + } + + cxx_method_decl->setParams (llvm::ArrayRef<clang::ParmVarDecl*>(params)); + + cxx_record_decl->addDecl (cxx_method_decl); + + // Sometimes the debug info will mention a constructor (default/copy/move), + // destructor, or assignment operator (copy/move) but there won't be any + // version of this in the code. So we check if the function was artificially + // generated and if it is trivial and this lets the compiler/backend know + // that it can inline the IR for these when it needs to and we can avoid a + // "missing function" error when running expressions. + + if (is_artificial) + { + if (cxx_ctor_decl && + ((cxx_ctor_decl->isDefaultConstructor() && cxx_record_decl->hasTrivialDefaultConstructor ()) || + (cxx_ctor_decl->isCopyConstructor() && cxx_record_decl->hasTrivialCopyConstructor ()) || + (cxx_ctor_decl->isMoveConstructor() && cxx_record_decl->hasTrivialMoveConstructor ()) )) + { + cxx_ctor_decl->setDefaulted(); + cxx_ctor_decl->setTrivial(true); + } + else if (cxx_dtor_decl) + { + if (cxx_record_decl->hasTrivialDestructor()) + { + cxx_dtor_decl->setDefaulted(); + cxx_dtor_decl->setTrivial(true); + } + } + else if ((cxx_method_decl->isCopyAssignmentOperator() && cxx_record_decl->hasTrivialCopyAssignment()) || + (cxx_method_decl->isMoveAssignmentOperator() && cxx_record_decl->hasTrivialMoveAssignment())) + { + cxx_method_decl->setDefaulted(); + cxx_method_decl->setTrivial(true); + } + } + +#ifdef LLDB_CONFIGURATION_DEBUG + VerifyDecl(cxx_method_decl); +#endif + + // printf ("decl->isPolymorphic() = %i\n", cxx_record_decl->isPolymorphic()); + // printf ("decl->isAggregate() = %i\n", cxx_record_decl->isAggregate()); + // printf ("decl->isPOD() = %i\n", cxx_record_decl->isPOD()); + // printf ("decl->isEmpty() = %i\n", cxx_record_decl->isEmpty()); + // printf ("decl->isAbstract() = %i\n", cxx_record_decl->isAbstract()); + // printf ("decl->hasTrivialConstructor() = %i\n", cxx_record_decl->hasTrivialConstructor()); + // printf ("decl->hasTrivialCopyConstructor() = %i\n", cxx_record_decl->hasTrivialCopyConstructor()); + // printf ("decl->hasTrivialCopyAssignment() = %i\n", cxx_record_decl->hasTrivialCopyAssignment()); + // printf ("decl->hasTrivialDestructor() = %i\n", cxx_record_decl->hasTrivialDestructor()); + return cxx_method_decl; +} + + +#pragma mark C++ Base Classes + +clang::CXXBaseSpecifier * +ClangASTContext::CreateBaseClassSpecifier (lldb::opaque_compiler_type_t type, AccessType access, bool is_virtual, bool base_of_class) +{ + if (type) + return new clang::CXXBaseSpecifier (clang::SourceRange(), + is_virtual, + base_of_class, + ClangASTContext::ConvertAccessTypeToAccessSpecifier (access), + getASTContext()->getTrivialTypeSourceInfo (GetQualType(type)), + clang::SourceLocation()); + return nullptr; +} + +void +ClangASTContext::DeleteBaseClassSpecifiers (clang::CXXBaseSpecifier **base_classes, unsigned num_base_classes) +{ + for (unsigned i=0; i<num_base_classes; ++i) + { + delete base_classes[i]; + base_classes[i] = nullptr; + } +} + +bool +ClangASTContext::SetBaseClassesForClassType (lldb::opaque_compiler_type_t type, clang::CXXBaseSpecifier const * const *base_classes, + unsigned num_base_classes) +{ + if (type) + { + clang::CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl(type); + if (cxx_record_decl) + { + cxx_record_decl->setBases(base_classes, num_base_classes); + return true; + } + } + return false; +} + +bool +ClangASTContext::SetObjCSuperClass (const CompilerType& type, const CompilerType &superclass_clang_type) +{ + ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(type.GetTypeSystem()); + if (!ast) + return false; + clang::ASTContext* clang_ast = ast->getASTContext(); + + if (type && superclass_clang_type.IsValid() && superclass_clang_type.GetTypeSystem() == type.GetTypeSystem()) + { + clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl (type); + clang::ObjCInterfaceDecl *super_interface_decl = GetAsObjCInterfaceDecl (superclass_clang_type); + if (class_interface_decl && super_interface_decl) + { + class_interface_decl->setSuperClass(clang_ast->getTrivialTypeSourceInfo(clang_ast->getObjCInterfaceType(super_interface_decl))); + return true; + } + } + return false; +} + +bool +ClangASTContext::AddObjCClassProperty (const CompilerType& type, + const char *property_name, + const CompilerType &property_clang_type, + clang::ObjCIvarDecl *ivar_decl, + const char *property_setter_name, + const char *property_getter_name, + uint32_t property_attributes, + ClangASTMetadata *metadata) +{ + if (!type || !property_clang_type.IsValid() || property_name == nullptr || property_name[0] == '\0') + return false; + ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (!ast) + return false; + clang::ASTContext* clang_ast = ast->getASTContext(); + + clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl (type); + + if (class_interface_decl) + { + CompilerType property_clang_type_to_access; + + if (property_clang_type.IsValid()) + property_clang_type_to_access = property_clang_type; + else if (ivar_decl) + property_clang_type_to_access = CompilerType (clang_ast, ivar_decl->getType()); + + if (class_interface_decl && property_clang_type_to_access.IsValid()) + { + clang::TypeSourceInfo *prop_type_source; + if (ivar_decl) + prop_type_source = clang_ast->getTrivialTypeSourceInfo (ivar_decl->getType()); else + prop_type_source = clang_ast->getTrivialTypeSourceInfo (GetQualType(property_clang_type)); + + clang::ObjCPropertyDecl *property_decl = clang::ObjCPropertyDecl::Create (*clang_ast, + class_interface_decl, + clang::SourceLocation(), // Source Location + &clang_ast->Idents.get(property_name), + clang::SourceLocation(), //Source Location for AT + clang::SourceLocation(), //Source location for ( + ivar_decl ? ivar_decl->getType() : ClangASTContext::GetQualType(property_clang_type), + prop_type_source); + + if (property_decl) { - language_object_name.SetCString("this"); - is_instance_method = true; + if (metadata) + ClangASTContext::SetMetadata(clang_ast, property_decl, *metadata); + + class_interface_decl->addDecl (property_decl); + + clang::Selector setter_sel, getter_sel; + + if (property_setter_name != nullptr) + { + std::string property_setter_no_colon(property_setter_name, strlen(property_setter_name) - 1); + clang::IdentifierInfo *setter_ident = &clang_ast->Idents.get(property_setter_no_colon.c_str()); + setter_sel = clang_ast->Selectors.getSelector(1, &setter_ident); + } + else if (!(property_attributes & DW_APPLE_PROPERTY_readonly)) + { + std::string setter_sel_string("set"); + setter_sel_string.push_back(::toupper(property_name[0])); + setter_sel_string.append(&property_name[1]); + clang::IdentifierInfo *setter_ident = &clang_ast->Idents.get(setter_sel_string.c_str()); + setter_sel = clang_ast->Selectors.getSelector(1, &setter_ident); + } + property_decl->setSetterName(setter_sel); + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_setter); + + if (property_getter_name != nullptr) + { + clang::IdentifierInfo *getter_ident = &clang_ast->Idents.get(property_getter_name); + getter_sel = clang_ast->Selectors.getSelector(0, &getter_ident); + } + else + { + clang::IdentifierInfo *getter_ident = &clang_ast->Idents.get(property_name); + getter_sel = clang_ast->Selectors.getSelector(0, &getter_ident); + } + property_decl->setGetterName(getter_sel); + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_getter); + + if (ivar_decl) + property_decl->setPropertyIvarDecl (ivar_decl); + + if (property_attributes & DW_APPLE_PROPERTY_readonly) + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_readonly); + if (property_attributes & DW_APPLE_PROPERTY_readwrite) + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_readwrite); + if (property_attributes & DW_APPLE_PROPERTY_assign) + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_assign); + if (property_attributes & DW_APPLE_PROPERTY_retain) + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_retain); + if (property_attributes & DW_APPLE_PROPERTY_copy) + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_copy); + if (property_attributes & DW_APPLE_PROPERTY_nonatomic) + property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_nonatomic); + + if (!getter_sel.isNull() && !class_interface_decl->lookupInstanceMethod(getter_sel)) + { + const bool isInstance = true; + const bool isVariadic = false; + const bool isSynthesized = false; + const bool isImplicitlyDeclared = true; + const bool isDefined = false; + const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None; + const bool HasRelatedResultType = false; + + clang::ObjCMethodDecl *getter = clang::ObjCMethodDecl::Create (*clang_ast, + clang::SourceLocation(), + clang::SourceLocation(), + getter_sel, + GetQualType(property_clang_type_to_access), + nullptr, + class_interface_decl, + isInstance, + isVariadic, + isSynthesized, + isImplicitlyDeclared, + isDefined, + impControl, + HasRelatedResultType); + + if (getter && metadata) + ClangASTContext::SetMetadata(clang_ast, getter, *metadata); + + if (getter) + { + getter->setMethodParams(*clang_ast, llvm::ArrayRef<clang::ParmVarDecl*>(), llvm::ArrayRef<clang::SourceLocation>()); + + class_interface_decl->addDecl(getter); + } + } + + if (!setter_sel.isNull() && !class_interface_decl->lookupInstanceMethod(setter_sel)) + { + clang::QualType result_type = clang_ast->VoidTy; + + const bool isInstance = true; + const bool isVariadic = false; + const bool isSynthesized = false; + const bool isImplicitlyDeclared = true; + const bool isDefined = false; + const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None; + const bool HasRelatedResultType = false; + + clang::ObjCMethodDecl *setter = clang::ObjCMethodDecl::Create (*clang_ast, + clang::SourceLocation(), + clang::SourceLocation(), + setter_sel, + result_type, + nullptr, + class_interface_decl, + isInstance, + isVariadic, + isSynthesized, + isImplicitlyDeclared, + isDefined, + impControl, + HasRelatedResultType); + + if (setter && metadata) + ClangASTContext::SetMetadata(clang_ast, setter, *metadata); + + llvm::SmallVector<clang::ParmVarDecl *, 1> params; + + params.push_back (clang::ParmVarDecl::Create (*clang_ast, + setter, + clang::SourceLocation(), + clang::SourceLocation(), + nullptr, // anonymous + GetQualType(property_clang_type_to_access), + nullptr, + clang::SC_Auto, + nullptr)); + + if (setter) + { + setter->setMethodParams(*clang_ast, llvm::ArrayRef<clang::ParmVarDecl*>(params), llvm::ArrayRef<clang::SourceLocation>()); + + class_interface_decl->addDecl(setter); + } + } + + return true; } - language = eLanguageTypeC_plus_plus; + } + } + return false; +} + +bool +ClangASTContext::IsObjCClassTypeAndHasIVars (const CompilerType& type, bool check_superclass) +{ + clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl (type); + if (class_interface_decl) + return ObjCDeclHasIVars (class_interface_decl, check_superclass); + return false; +} + + +clang::ObjCMethodDecl * +ClangASTContext::AddMethodToObjCObjectType (const CompilerType& type, + const char *name, // the full symbol name as seen in the symbol table (lldb::opaque_compiler_type_t type, "-[NString stringWithCString:]") + const CompilerType &method_clang_type, + lldb::AccessType access, + bool is_artificial) +{ + if (!type || !method_clang_type.IsValid()) + return nullptr; + + clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type); + + if (class_interface_decl == nullptr) + return nullptr; + ClangASTContext *lldb_ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (lldb_ast == nullptr) + return nullptr; + clang::ASTContext *ast = lldb_ast->getASTContext(); + + const char *selector_start = ::strchr (name, ' '); + if (selector_start == nullptr) + return nullptr; + + selector_start++; + llvm::SmallVector<clang::IdentifierInfo *, 12> selector_idents; + + size_t len = 0; + const char *start; + //printf ("name = '%s'\n", name); + + unsigned num_selectors_with_args = 0; + for (start = selector_start; + start && *start != '\0' && *start != ']'; + start += len) + { + len = ::strcspn(start, ":]"); + bool has_arg = (start[len] == ':'); + if (has_arg) + ++num_selectors_with_args; + selector_idents.push_back (&ast->Idents.get (llvm::StringRef (start, len))); + if (has_arg) + len += 1; + } + + + if (selector_idents.size() == 0) + return nullptr; + + clang::Selector method_selector = ast->Selectors.getSelector (num_selectors_with_args ? selector_idents.size() : 0, + selector_idents.data()); + + clang::QualType method_qual_type (GetQualType(method_clang_type)); + + // Populate the method decl with parameter decls + const clang::Type *method_type(method_qual_type.getTypePtr()); + + if (method_type == nullptr) + return nullptr; + + const clang::FunctionProtoType *method_function_prototype (llvm::dyn_cast<clang::FunctionProtoType>(method_type)); + + if (!method_function_prototype) + return nullptr; + + + bool is_variadic = false; + bool is_synthesized = false; + bool is_defined = false; + clang::ObjCMethodDecl::ImplementationControl imp_control = clang::ObjCMethodDecl::None; + + const unsigned num_args = method_function_prototype->getNumParams(); + + if (num_args != num_selectors_with_args) + return nullptr; // some debug information is corrupt. We are not going to deal with it. + + clang::ObjCMethodDecl *objc_method_decl = clang::ObjCMethodDecl::Create (*ast, + clang::SourceLocation(), // beginLoc, + clang::SourceLocation(), // endLoc, + method_selector, + method_function_prototype->getReturnType(), + nullptr, // TypeSourceInfo *ResultTInfo, + ClangASTContext::GetASTContext(ast)->GetDeclContextForType(GetQualType(type)), + name[0] == '-', + is_variadic, + is_synthesized, + true, // is_implicitly_declared; we force this to true because we don't have source locations + is_defined, + imp_control, + false /*has_related_result_type*/); + + + if (objc_method_decl == nullptr) + return nullptr; + + if (num_args > 0) + { + llvm::SmallVector<clang::ParmVarDecl *, 12> params; + + for (unsigned param_index = 0; param_index < num_args; ++param_index) + { + params.push_back (clang::ParmVarDecl::Create (*ast, + objc_method_decl, + clang::SourceLocation(), + clang::SourceLocation(), + nullptr, // anonymous + method_function_prototype->getParamType(param_index), + nullptr, + clang::SC_Auto, + nullptr)); + } + + objc_method_decl->setMethodParams(*ast, llvm::ArrayRef<clang::ParmVarDecl*>(params), llvm::ArrayRef<clang::SourceLocation>()); + } + + class_interface_decl->addDecl (objc_method_decl); + +#ifdef LLDB_CONFIGURATION_DEBUG + VerifyDecl(objc_method_decl); +#endif + + return objc_method_decl; +} + +bool +ClangASTContext::GetHasExternalStorage (const CompilerType &type) +{ + if (IsClangType(type)) + return false; + + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + { + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + return cxx_record_decl->hasExternalLexicalStorage () || cxx_record_decl->hasExternalVisibleStorage(); + } + break; + + case clang::Type::Enum: + { + clang::EnumDecl *enum_decl = llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) + return enum_decl->hasExternalLexicalStorage () || enum_decl->hasExternalVisibleStorage(); + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + return class_interface_decl->hasExternalLexicalStorage () || class_interface_decl->hasExternalVisibleStorage (); + } + } + break; + + case clang::Type::Typedef: + return GetHasExternalStorage (CompilerType(type.GetTypeSystem(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr())); + + case clang::Type::Auto: + return GetHasExternalStorage (CompilerType(type.GetTypeSystem(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr())); + + case clang::Type::Elaborated: + return GetHasExternalStorage (CompilerType(type.GetTypeSystem(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr())); + + case clang::Type::Paren: + return GetHasExternalStorage (CompilerType(type.GetTypeSystem(), llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); + + default: + break; + } + return false; +} + + +bool +ClangASTContext::SetHasExternalStorage (lldb::opaque_compiler_type_t type, bool has_extern) +{ + if (!type) + return false; + + clang::QualType qual_type (GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + { + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + cxx_record_decl->setHasExternalLexicalStorage (has_extern); + cxx_record_decl->setHasExternalVisibleStorage (has_extern); + return true; + } + } + break; + + case clang::Type::Enum: + { + clang::EnumDecl *enum_decl = llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) + { + enum_decl->setHasExternalLexicalStorage (has_extern); + enum_decl->setHasExternalVisibleStorage (has_extern); + return true; + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + { + class_interface_decl->setHasExternalLexicalStorage (has_extern); + class_interface_decl->setHasExternalVisibleStorage (has_extern); + return true; + } + } + } + break; + + case clang::Type::Typedef: + return SetHasExternalStorage(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), has_extern); + + case clang::Type::Auto: + return SetHasExternalStorage (llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr(), has_extern); + + case clang::Type::Elaborated: + return SetHasExternalStorage (llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), has_extern); + + case clang::Type::Paren: + return SetHasExternalStorage (llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr(), has_extern); + + default: + break; + } + return false; +} + + +bool +ClangASTContext::CanImport (const CompilerType &type, lldb_private::ClangASTImporter &importer) +{ + if (IsClangType(type)) + { + // TODO: remove external completion BOOL + // CompleteAndFetchChildren should get the Decl out and check for the + + clang::QualType qual_type(GetCanonicalQualType(RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + if (importer.ResolveDeclOrigin (cxx_record_decl, NULL, NULL)) + return true; + } + } + break; + + case clang::Type::Enum: + { + clang::EnumDecl *enum_decl = llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) + { + if (importer.ResolveDeclOrigin (enum_decl, NULL, NULL)) + return true; + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added ASTContext + // because it only supports TagDecl objects right now... + if (class_interface_decl) + { + if (importer.ResolveDeclOrigin (class_interface_decl, NULL, NULL)) + return true; + } + } + } + break; + + + case clang::Type::Typedef: + return CanImport(CompilerType (type.GetTypeSystem(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr()), importer); + + case clang::Type::Auto: + return CanImport(CompilerType (type.GetTypeSystem(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr()), importer); + + case clang::Type::Elaborated: + return CanImport(CompilerType (type.GetTypeSystem(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr()), importer); + + case clang::Type::Paren: + return CanImport(CompilerType (type.GetTypeSystem(), llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()), importer); + + default: + break; + } + } + return false; +} +bool +ClangASTContext::Import (const CompilerType &type, lldb_private::ClangASTImporter &importer) +{ + if (IsClangType(type)) + { + // TODO: remove external completion BOOL + // CompleteAndFetchChildren should get the Decl out and check for the + + clang::QualType qual_type(GetCanonicalQualType(RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + if (importer.ResolveDeclOrigin (cxx_record_decl, NULL, NULL)) + return importer.CompleteAndFetchChildren(qual_type); + } + } + break; + + case clang::Type::Enum: + { + clang::EnumDecl *enum_decl = llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) + { + if (importer.ResolveDeclOrigin (enum_decl, NULL, NULL)) + return importer.CompleteAndFetchChildren(qual_type); + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added ASTContext + // because it only supports TagDecl objects right now... + if (class_interface_decl) + { + if (importer.ResolveDeclOrigin (class_interface_decl, NULL, NULL)) + return importer.CompleteAndFetchChildren(qual_type); + } + } + } + break; + + + case clang::Type::Typedef: + return Import (CompilerType(type.GetTypeSystem(), llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr()), importer); + + case clang::Type::Auto: + return Import (CompilerType(type.GetTypeSystem(),llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr()), importer); + + case clang::Type::Elaborated: + return Import (CompilerType(type.GetTypeSystem(),llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr()), importer); + + case clang::Type::Paren: + return Import (CompilerType(type.GetTypeSystem(),llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()), importer); + + default: + break; + } + } + return false; +} + + +#pragma mark TagDecl + +bool +ClangASTContext::StartTagDeclarationDefinition (const CompilerType &type) +{ + clang::QualType qual_type (ClangASTContext::GetQualType(type)); + if (!qual_type.isNull()) + { + const clang::TagType *tag_type = qual_type->getAs<clang::TagType>(); + if (tag_type) + { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + { + tag_decl->startDefinition(); + return true; + } + } + + const clang::ObjCObjectType *object_type = qual_type->getAs<clang::ObjCObjectType>(); + if (object_type) + { + clang::ObjCInterfaceDecl *interface_decl = object_type->getInterface(); + if (interface_decl) + { + interface_decl->startDefinition(); + return true; + } + } + } + return false; +} + +bool +ClangASTContext::CompleteTagDeclarationDefinition (const CompilerType& type) +{ + clang::QualType qual_type (ClangASTContext::GetQualType(type)); + if (!qual_type.isNull()) + { + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + + if (cxx_record_decl) + { + if (!cxx_record_decl->isCompleteDefinition()) + cxx_record_decl->completeDefinition(); + cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true); + cxx_record_decl->setHasExternalLexicalStorage (false); + cxx_record_decl->setHasExternalVisibleStorage (false); return true; } - else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx)) + + const clang::EnumType *enutype = qual_type->getAs<clang::EnumType>(); + + if (enutype) { - // Both static and instance methods have a "self" object in objective C - language_object_name.SetCString("self"); - if (method_decl->isInstanceMethod()) + clang::EnumDecl *enum_decl = enutype->getDecl(); + + if (enum_decl) { - is_instance_method = true; + if (!enum_decl->isCompleteDefinition()) + { + ClangASTContext *lldb_ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (lldb_ast == nullptr) + return false; + clang::ASTContext *ast = lldb_ast->getASTContext(); + + /// TODO This really needs to be fixed. + + unsigned NumPositiveBits = 1; + unsigned NumNegativeBits = 0; + + clang::QualType promotion_qual_type; + // If the enum integer type is less than an integer in bit width, + // then we must promote it to an integer size. + if (ast->getTypeSize(enum_decl->getIntegerType()) < ast->getTypeSize(ast->IntTy)) + { + if (enum_decl->getIntegerType()->isSignedIntegerType()) + promotion_qual_type = ast->IntTy; + else + promotion_qual_type = ast->UnsignedIntTy; + } + else + promotion_qual_type = enum_decl->getIntegerType(); + + enum_decl->completeDefinition(enum_decl->getIntegerType(), promotion_qual_type, NumPositiveBits, NumNegativeBits); + } + return true; + } + } + } + return false; +} + +bool +ClangASTContext::AddEnumerationValueToEnumerationType (lldb::opaque_compiler_type_t type, + const CompilerType &enumerator_clang_type, + const Declaration &decl, + const char *name, + int64_t enum_value, + uint32_t enum_value_bit_size) +{ + if (type && enumerator_clang_type.IsValid() && name && name[0]) + { + clang::QualType enum_qual_type (GetCanonicalQualType(type)); + + bool is_signed = false; + enumerator_clang_type.IsIntegerType (is_signed); + const clang::Type *clang_type = enum_qual_type.getTypePtr(); + if (clang_type) + { + const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(clang_type); + + if (enutype) + { + llvm::APSInt enum_llvm_apsint(enum_value_bit_size, is_signed); + enum_llvm_apsint = enum_value; + clang::EnumConstantDecl *enumerator_decl = + clang::EnumConstantDecl::Create (*getASTContext(), + enutype->getDecl(), + clang::SourceLocation(), + name ? &getASTContext()->Idents.get(name) : nullptr, // Identifier + GetQualType(enumerator_clang_type), + nullptr, + enum_llvm_apsint); + + if (enumerator_decl) + { + enutype->getDecl()->addDecl(enumerator_decl); + +#ifdef LLDB_CONFIGURATION_DEBUG + VerifyDecl(enumerator_decl); +#endif + + return true; + } + } + } + } + return false; +} + +CompilerType +ClangASTContext::GetEnumerationIntegerType (lldb::opaque_compiler_type_t type) +{ + clang::QualType enum_qual_type (GetCanonicalQualType(type)); + const clang::Type *clang_type = enum_qual_type.getTypePtr(); + if (clang_type) + { + const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(clang_type); + if (enutype) + { + clang::EnumDecl *enum_decl = enutype->getDecl(); + if (enum_decl) + return CompilerType (getASTContext(), enum_decl->getIntegerType()); + } + } + return CompilerType(); +} + +CompilerType +ClangASTContext::CreateMemberPointerType (const CompilerType& type, const CompilerType &pointee_type) +{ + if (type && pointee_type.IsValid() && type.GetTypeSystem() == pointee_type.GetTypeSystem()) + { + ClangASTContext *ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); + if (!ast) + return CompilerType(); + return CompilerType (ast->getASTContext(), + ast->getASTContext()->getMemberPointerType (GetQualType(pointee_type), + GetQualType(type).getTypePtr())); + } + return CompilerType(); +} + + +size_t +ClangASTContext::ConvertStringToFloatValue (lldb::opaque_compiler_type_t type, const char *s, uint8_t *dst, size_t dst_size) +{ + if (type) + { + clang::QualType qual_type (GetCanonicalQualType(type)); + uint32_t count = 0; + bool is_complex = false; + if (IsFloatingPointType (type, count, is_complex)) + { + // TODO: handle complex and vector types + if (count != 1) + return false; + + llvm::StringRef s_sref(s); + llvm::APFloat ap_float(getASTContext()->getFloatTypeSemantics(qual_type), s_sref); + + const uint64_t bit_size = getASTContext()->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; +} + + + +//---------------------------------------------------------------------- +// Dumping types +//---------------------------------------------------------------------- +#define DEPTH_INCREMENT 2 + +void +ClangASTContext::DumpValue (lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, + Stream *s, + lldb::Format format, + const lldb_private::DataExtractor &data, + lldb::offset_t data_byte_offset, + size_t data_byte_size, + uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, + bool show_types, + bool show_summary, + bool verbose, + uint32_t depth) +{ + if (!type) + return; + + clang::QualType qual_type(GetQualType(type)); + switch (qual_type->getTypeClass()) + { + case clang::Type::Record: + if (GetCompleteType(type)) + { + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + uint32_t field_bit_offset = 0; + uint32_t field_byte_offset = 0; + const clang::ASTRecordLayout &record_layout = getASTContext()->getASTRecordLayout(record_decl); + uint32_t child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + // We might have base classes to print out first + clang::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 clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + + // Skip empty base classes + if (verbose == false && ClangASTContext::RecordHasFields(base_class_decl) == false) + continue; + + if (base_class->isVirtual()) + field_bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8; + else + field_bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8; + field_byte_offset = field_bit_offset / 8; + assert (field_bit_offset % 8 == 0); + if (child_idx == 0) + s->PutChar('{'); + else + s->PutChar(','); + + clang::QualType base_class_qual_type = base_class->getType(); + std::string base_class_type_name(base_class_qual_type.getAsString()); + + // Indent and print the base class type name + s->Printf("\n%*s%s ", depth + DEPTH_INCREMENT, "", base_class_type_name.c_str()); + + clang::TypeInfo base_class_type_info = getASTContext()->getTypeInfo(base_class_qual_type); + + // Dump the value of the member + CompilerType base_clang_type(getASTContext(), base_class_qual_type); + base_clang_type.DumpValue (exe_ctx, + s, // Stream to dump to + base_clang_type.GetFormat(), // The format with which to display the member + data, // Data buffer containing all bytes for this type + data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from + base_class_type_info.Width / 8, // Size of this type in bytes + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth + DEPTH_INCREMENT); // Scope depth for any types that have children + + ++child_idx; + } + } + uint32_t field_idx = 0; + clang::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) + { + // Print the starting squiggly bracket (if this is the + // first member) or comma (for member 2 and beyond) for + // the struct/union/class member. + if (child_idx == 0) + s->PutChar('{'); + else + s->PutChar(','); + + // Indent + s->Printf("\n%*s", depth + DEPTH_INCREMENT, ""); + + clang::QualType field_type = field->getType(); + // Print the member type if requested + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + clang::TypeInfo field_type_info = getASTContext()->getTypeInfo(field_type); + assert(field_idx < record_layout.getFieldCount()); + // Figure out the field offset within the current struct/union/class type + field_bit_offset = record_layout.getFieldOffset (field_idx); + field_byte_offset = field_bit_offset / 8; + uint32_t field_bitfield_bit_size = 0; + uint32_t field_bitfield_bit_offset = 0; + if (ClangASTContext::FieldIsBitfield (getASTContext(), *field, field_bitfield_bit_size)) + field_bitfield_bit_offset = field_bit_offset % 8; + + if (show_types) + { + std::string field_type_name(field_type.getAsString()); + if (field_bitfield_bit_size > 0) + s->Printf("(%s:%u) ", field_type_name.c_str(), field_bitfield_bit_size); + else + s->Printf("(%s) ", field_type_name.c_str()); + } + // Print the member name and equal sign + s->Printf("%s = ", field->getNameAsString().c_str()); + + + // Dump the value of the member + CompilerType field_clang_type (getASTContext(), field_type); + field_clang_type.DumpValue (exe_ctx, + s, // Stream to dump to + field_clang_type.GetFormat(), // The format with which to display the member + data, // Data buffer containing all bytes for this type + data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from + field_type_info.Width / 8, // Size of this type in bytes + field_bitfield_bit_size, // Bitfield bit size + field_bitfield_bit_offset, // Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth + DEPTH_INCREMENT); // Scope depth for any types that have children + } + + // Indent the trailing squiggly bracket + if (child_idx > 0) + s->Printf("\n%*s}", depth, ""); + } + return; + + case clang::Type::Enum: + if (GetCompleteType(type)) + { + const clang::EnumType *enutype = llvm::cast<clang::EnumType>(qual_type.getTypePtr()); + const clang::EnumDecl *enum_decl = enutype->getDecl(); + assert(enum_decl); + clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; + lldb::offset_t offset = data_byte_offset; + const int64_t enum_value = data.GetMaxU64Bitfield(&offset, data_byte_size, bitfield_bit_size, bitfield_bit_offset); + for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos) + { + if (enum_pos->getInitVal() == enum_value) + { + s->Printf("%s", enum_pos->getNameAsString().c_str()); + return; + } + } + // If we have gotten here we didn't get find the enumerator in the + // enum decl, so just print the integer. + s->Printf("%" PRIi64, enum_value); + } + return; + + case clang::Type::ConstantArray: + { + const clang::ConstantArrayType *array = llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr()); + bool is_array_of_characters = false; + clang::QualType element_qual_type = array->getElementType(); + + const clang::Type *canonical_type = element_qual_type->getCanonicalTypeInternal().getTypePtr(); + if (canonical_type) + is_array_of_characters = canonical_type->isCharType(); + + const uint64_t element_count = array->getSize().getLimitedValue(); + + clang::TypeInfo field_type_info = getASTContext()->getTypeInfo(element_qual_type); + + uint32_t element_idx = 0; + uint32_t element_offset = 0; + uint64_t element_byte_size = field_type_info.Width / 8; + uint32_t element_stride = element_byte_size; + + if (is_array_of_characters) + { + s->PutChar('"'); + data.Dump(s, data_byte_offset, lldb::eFormatChar, element_byte_size, element_count, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0); + s->PutChar('"'); + return; } else { - is_instance_method = false; + CompilerType element_clang_type(getASTContext(), element_qual_type); + lldb::Format element_format = element_clang_type.GetFormat(); + + for (element_idx = 0; element_idx < element_count; ++element_idx) + { + // Print the starting squiggly bracket (if this is the + // first member) or comman (for member 2 and beyong) for + // the struct/union/class member. + if (element_idx == 0) + s->PutChar('{'); + else + s->PutChar(','); + + // Indent and print the index + s->Printf("\n%*s[%u] ", depth + DEPTH_INCREMENT, "", element_idx); + + // Figure out the field offset within the current struct/union/class type + element_offset = element_idx * element_stride; + + // Dump the value of the member + element_clang_type.DumpValue (exe_ctx, + s, // Stream to dump to + element_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + data_byte_offset + element_offset,// Offset into "data" where to grab value from + element_byte_size, // Size of this type in bytes + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth + DEPTH_INCREMENT); // Scope depth for any types that have children + } + + // Indent the trailing squiggly bracket + if (element_idx > 0) + s->Printf("\n%*s}", depth, ""); + } + } + return; + + case clang::Type::Typedef: + { + clang::QualType typedef_qual_type = llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType(); + + CompilerType typedef_clang_type (getASTContext(), typedef_qual_type); + lldb::Format typedef_format = typedef_clang_type.GetFormat(); + clang::TypeInfo typedef_type_info = getASTContext()->getTypeInfo(typedef_qual_type); + uint64_t typedef_byte_size = typedef_type_info.Width / 8; + + return typedef_clang_type.DumpValue (exe_ctx, + s, // Stream to dump to + typedef_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + data_byte_offset, // Offset into "data" where to grab value from + typedef_byte_size, // Size of this type in bytes + bitfield_bit_size, // Bitfield bit size + bitfield_bit_offset,// Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth); // Scope depth for any types that have children + } + break; + + case clang::Type::Auto: + { + clang::QualType elaborated_qual_type = llvm::cast<clang::AutoType>(qual_type)->getDeducedType(); + CompilerType elaborated_clang_type (getASTContext(), elaborated_qual_type); + lldb::Format elaborated_format = elaborated_clang_type.GetFormat(); + clang::TypeInfo elaborated_type_info = getASTContext()->getTypeInfo(elaborated_qual_type); + uint64_t elaborated_byte_size = elaborated_type_info.Width / 8; + + return elaborated_clang_type.DumpValue (exe_ctx, + s, // Stream to dump to + elaborated_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + data_byte_offset, // Offset into "data" where to grab value from + elaborated_byte_size, // Size of this type in bytes + bitfield_bit_size, // Bitfield bit size + bitfield_bit_offset,// Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth); // Scope depth for any types that have children + } + break; + + case clang::Type::Elaborated: + { + clang::QualType elaborated_qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType(); + CompilerType elaborated_clang_type (getASTContext(), elaborated_qual_type); + lldb::Format elaborated_format = elaborated_clang_type.GetFormat(); + clang::TypeInfo elaborated_type_info = getASTContext()->getTypeInfo(elaborated_qual_type); + uint64_t elaborated_byte_size = elaborated_type_info.Width / 8; + + return elaborated_clang_type.DumpValue (exe_ctx, + s, // Stream to dump to + elaborated_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + data_byte_offset, // Offset into "data" where to grab value from + elaborated_byte_size, // Size of this type in bytes + bitfield_bit_size, // Bitfield bit size + bitfield_bit_offset,// Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth); // Scope depth for any types that have children + } + break; + + case clang::Type::Paren: + { + clang::QualType desugar_qual_type = llvm::cast<clang::ParenType>(qual_type)->desugar(); + CompilerType desugar_clang_type (getASTContext(), desugar_qual_type); + + lldb::Format desugar_format = desugar_clang_type.GetFormat(); + clang::TypeInfo desugar_type_info = getASTContext()->getTypeInfo(desugar_qual_type); + uint64_t desugar_byte_size = desugar_type_info.Width / 8; + + return desugar_clang_type.DumpValue (exe_ctx, + s, // Stream to dump to + desugar_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + data_byte_offset, // Offset into "data" where to grab value from + desugar_byte_size, // Size of this type in bytes + bitfield_bit_size, // Bitfield bit size + bitfield_bit_offset,// Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth); // Scope depth for any types that have children + } + break; + + default: + // We are down to a scalar type that we just need to display. + data.Dump(s, + data_byte_offset, + format, + data_byte_size, + 1, + UINT32_MAX, + LLDB_INVALID_ADDRESS, + bitfield_bit_size, + bitfield_bit_offset); + + if (show_summary) + DumpSummary (type, exe_ctx, s, data, data_byte_offset, data_byte_size); + break; + } +} + + + + +bool +ClangASTContext::DumpTypeValue (lldb::opaque_compiler_type_t type, Stream *s, + lldb::Format format, + const lldb_private::DataExtractor &data, + lldb::offset_t byte_offset, + size_t byte_size, + uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, + ExecutionContextScope *exe_scope) +{ + if (!type) + return false; + if (IsAggregateType(type)) + { + return false; + } + else + { + clang::QualType qual_type(GetQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Typedef: + { + clang::QualType typedef_qual_type = llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType(); + CompilerType typedef_clang_type (getASTContext(), typedef_qual_type); + if (format == eFormatDefault) + format = typedef_clang_type.GetFormat(); + clang::TypeInfo typedef_type_info = getASTContext()->getTypeInfo(typedef_qual_type); + uint64_t typedef_byte_size = typedef_type_info.Width / 8; + + return typedef_clang_type.DumpTypeValue (s, + format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + byte_offset, // Offset into "data" where to grab value from + typedef_byte_size, // Size of this type in bytes + bitfield_bit_size, // Size in bits of a bitfield value, if zero don't treat as a bitfield + bitfield_bit_offset, // Offset in bits of a bitfield value if bitfield_bit_size != 0 + exe_scope); + } + break; + + case clang::Type::Enum: + // If our format is enum or default, show the enumeration value as + // its enumeration string value, else just display it as requested. + if ((format == eFormatEnum || format == eFormatDefault) && GetCompleteType(type)) + { + const clang::EnumType *enutype = llvm::cast<clang::EnumType>(qual_type.getTypePtr()); + const clang::EnumDecl *enum_decl = enutype->getDecl(); + assert(enum_decl); + clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; + const bool is_signed = qual_type->isSignedIntegerOrEnumerationType(); + lldb::offset_t offset = byte_offset; + if (is_signed) + { + const int64_t enum_svalue = data.GetMaxS64Bitfield (&offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos) + { + if (enum_pos->getInitVal().getSExtValue() == enum_svalue) + { + s->PutCString (enum_pos->getNameAsString().c_str()); + return true; + } + } + // If we have gotten here we didn't get find the enumerator in the + // enum decl, so just print the integer. + s->Printf("%" PRIi64, enum_svalue); + } + else + { + const uint64_t enum_uvalue = data.GetMaxU64Bitfield (&offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos) + { + if (enum_pos->getInitVal().getZExtValue() == enum_uvalue) + { + s->PutCString (enum_pos->getNameAsString().c_str()); + return true; + } + } + // If we have gotten here we didn't get find the enumerator in the + // enum decl, so just print the integer. + s->Printf("%" PRIu64, enum_uvalue); + } + return true; + } + // format was not enum, just fall through and dump the value as requested.... + + default: + // We are down to a scalar type that we just need to display. + { + uint32_t item_count = 1; + // A few formats, we might need to modify our size and count for depending + // on how we are trying to display the value... + switch (format) + { + default: + case eFormatBoolean: + case eFormatBinary: + case eFormatComplex: + case eFormatCString: // NULL terminated C strings + case eFormatDecimal: + case eFormatEnum: + case eFormatHex: + case eFormatHexUppercase: + case eFormatFloat: + case eFormatOctal: + case eFormatOSType: + case eFormatUnsigned: + case eFormatPointer: + case eFormatVectorOfChar: + case eFormatVectorOfSInt8: + case eFormatVectorOfUInt8: + case eFormatVectorOfSInt16: + case eFormatVectorOfUInt16: + case eFormatVectorOfSInt32: + case eFormatVectorOfUInt32: + case eFormatVectorOfSInt64: + case eFormatVectorOfUInt64: + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + case eFormatVectorOfUInt128: + break; + + case eFormatChar: + case eFormatCharPrintable: + case eFormatCharArray: + case eFormatBytes: + case eFormatBytesWithASCII: + item_count = byte_size; + byte_size = 1; + break; + + case eFormatUnicode16: + item_count = byte_size / 2; + byte_size = 2; + break; + + case eFormatUnicode32: + item_count = byte_size / 4; + byte_size = 4; + break; + } + return data.Dump (s, + byte_offset, + format, + byte_size, + item_count, + UINT32_MAX, + LLDB_INVALID_ADDRESS, + bitfield_bit_size, + bitfield_bit_offset, + exe_scope); + } + break; + } + } + return 0; +} + + + +void +ClangASTContext::DumpSummary (lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, + Stream *s, + const lldb_private::DataExtractor &data, + lldb::offset_t data_byte_offset, + size_t data_byte_size) +{ + uint32_t length = 0; + if (IsCStringType (type, length)) + { + if (exe_ctx) + { + Process *process = exe_ctx->GetProcessPtr(); + if (process) + { + lldb::offset_t offset = data_byte_offset; + lldb::addr_t pointer_address = data.GetMaxU64(&offset, data_byte_size); + std::vector<uint8_t> buf; + if (length > 0) + buf.resize (length); + else + buf.resize (256); + + lldb_private::DataExtractor cstr_data(&buf.front(), buf.size(), process->GetByteOrder(), 4); + buf.back() = '\0'; + size_t bytes_read; + size_t total_cstr_len = 0; + Error error; + while ((bytes_read = process->ReadMemory (pointer_address, &buf.front(), buf.size(), error)) > 0) + { + const size_t len = strlen((const char *)&buf.front()); + if (len == 0) + break; + if (total_cstr_len == 0) + s->PutCString (" \""); + cstr_data.Dump(s, 0, lldb::eFormatChar, 1, len, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0); + total_cstr_len += len; + if (len < buf.size()) + break; + pointer_address += total_cstr_len; + } + if (total_cstr_len > 0) + s->PutChar ('"'); + } + } + } +} + +void +ClangASTContext::DumpTypeDescription (lldb::opaque_compiler_type_t type) +{ + StreamFile s (stdout, false); + DumpTypeDescription (type, &s); + ClangASTMetadata *metadata = ClangASTContext::GetMetadata (getASTContext(), type); + if (metadata) + { + metadata->Dump (&s); + } +} + +void +ClangASTContext::DumpTypeDescription (lldb::opaque_compiler_type_t type, Stream *s) +{ + if (type) + { + clang::QualType qual_type(GetQualType(type)); + + llvm::SmallVector<char, 1024> buf; + llvm::raw_svector_ostream llvm_ostrm (buf); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + GetCompleteType(type); + + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + if (class_interface_decl) + { + clang::PrintingPolicy policy = getASTContext()->getPrintingPolicy(); + class_interface_decl->print(llvm_ostrm, policy, s->GetIndentLevel()); + } + } + } + break; + + case clang::Type::Typedef: + { + const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (typedef_type) + { + const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + std::string clang_typedef_name (typedef_decl->getQualifiedNameAsString()); + if (!clang_typedef_name.empty()) + { + s->PutCString ("typedef "); + s->PutCString (clang_typedef_name.c_str()); + } + } + } + break; + + case clang::Type::Auto: + CompilerType (getASTContext(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType()).DumpTypeDescription(s); + return; + + case clang::Type::Elaborated: + CompilerType (getASTContext(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).DumpTypeDescription(s); + return; + + case clang::Type::Paren: + CompilerType (getASTContext(), llvm::cast<clang::ParenType>(qual_type)->desugar()).DumpTypeDescription(s); + return; + + case clang::Type::Record: + { + GetCompleteType(type); + + const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + + if (cxx_record_decl) + cxx_record_decl->print(llvm_ostrm, getASTContext()->getPrintingPolicy(), s->GetIndentLevel()); + else + record_decl->print(llvm_ostrm, getASTContext()->getPrintingPolicy(), s->GetIndentLevel()); + } + break; + + default: + { + const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()); + if (tag_type) + { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + tag_decl->print(llvm_ostrm, 0); + } + else + { + std::string clang_type_name(qual_type.getAsString()); + if (!clang_type_name.empty()) + s->PutCString (clang_type_name.c_str()); + } + } + } + + if (buf.size() > 0) + { + s->Write (buf.data(), buf.size()); + } + } +} + +void +ClangASTContext::DumpTypeName (const CompilerType &type) +{ + if (IsClangType(type)) + { + clang::QualType qual_type(GetCanonicalQualType(RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + { + const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + printf("class %s", cxx_record_decl->getName().str().c_str()); + } + break; + + case clang::Type::Enum: + { + clang::EnumDecl *enum_decl = llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) + { + printf("enum %s", enum_decl->getName().str().c_str()); + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added ASTContext + // because it only supports TagDecl objects right now... + if (class_interface_decl) + printf("@class %s", class_interface_decl->getName().str().c_str()); + } + } + break; + + + case clang::Type::Typedef: + printf("typedef %s", llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getName().str().c_str()); + break; + + case clang::Type::Auto: + printf("auto "); + return DumpTypeName (CompilerType (type.GetTypeSystem(), llvm::cast<clang::AutoType>(qual_type)->getDeducedType().getAsOpaquePtr())); + + case clang::Type::Elaborated: + printf("elaborated "); + return DumpTypeName (CompilerType (type.GetTypeSystem(), llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr())); + + case clang::Type::Paren: + printf("paren "); + return DumpTypeName (CompilerType (type.GetTypeSystem(), llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); + + default: + printf("ClangASTContext::DumpTypeName() type_class = %u", type_class); + break; + } + } + +} + + + +clang::ClassTemplateDecl * +ClangASTContext::ParseClassTemplateDecl (clang::DeclContext *decl_ctx, + lldb::AccessType access_type, + const char *parent_name, + int tag_decl_kind, + const ClangASTContext::TemplateParameterInfos &template_param_infos) +{ + if (template_param_infos.IsValid()) + { + std::string template_basename(parent_name); + template_basename.erase (template_basename.find('<')); + + return CreateClassTemplateDecl (decl_ctx, + access_type, + template_basename.c_str(), + tag_decl_kind, + template_param_infos); + } + return NULL; +} + +void +ClangASTContext::CompleteTagDecl (void *baton, clang::TagDecl *decl) +{ + ClangASTContext *ast = (ClangASTContext *)baton; + SymbolFile *sym_file = ast->GetSymbolFile(); + if (sym_file) + { + CompilerType clang_type = GetTypeForDecl (decl); + if (clang_type) + sym_file->CompleteType (clang_type); + } +} + +void +ClangASTContext::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl) +{ + ClangASTContext *ast = (ClangASTContext *)baton; + SymbolFile *sym_file = ast->GetSymbolFile(); + if (sym_file) + { + CompilerType clang_type = GetTypeForDecl (decl); + if (clang_type) + sym_file->CompleteType (clang_type); + } +} + + +DWARFASTParser * +ClangASTContext::GetDWARFParser () +{ + if (!m_dwarf_ast_parser_ap) + m_dwarf_ast_parser_ap.reset(new DWARFASTParserClang(*this)); + return m_dwarf_ast_parser_ap.get(); +} + + +bool +ClangASTContext::LayoutRecordType(void *baton, + const clang::RecordDecl *record_decl, + uint64_t &bit_size, + uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets) +{ + ClangASTContext *ast = (ClangASTContext *)baton; + DWARFASTParserClang *dwarf_ast_parser = (DWARFASTParserClang *)ast->GetDWARFParser(); + return dwarf_ast_parser->LayoutRecordType(record_decl, bit_size, alignment, field_offsets, base_offsets, vbase_offsets); +} + +//---------------------------------------------------------------------- +// CompilerDecl override functions +//---------------------------------------------------------------------- +lldb::VariableSP +ClangASTContext::DeclGetVariable (void *opaque_decl) +{ + if (llvm::dyn_cast<clang::VarDecl>((clang::Decl *)opaque_decl)) + { + auto decl_search_it = m_decl_objects.find(opaque_decl); + if (decl_search_it != m_decl_objects.end()) + return std::static_pointer_cast<Variable>(decl_search_it->second); + } + return VariableSP(); +} + +void +ClangASTContext::DeclLinkToObject (void *opaque_decl, std::shared_ptr<void> object) +{ + if (m_decl_objects.find(opaque_decl) == m_decl_objects.end()) + m_decl_objects.insert(std::make_pair(opaque_decl, object)); +} + +ConstString +ClangASTContext::DeclGetName (void *opaque_decl) +{ + if (opaque_decl) + { + clang::NamedDecl *nd = llvm::dyn_cast<NamedDecl>((clang::Decl*)opaque_decl); + if (nd != nullptr) + return ConstString(nd->getDeclName().getAsString()); + } + return ConstString(); +} + +ConstString +ClangASTContext::DeclGetMangledName (void *opaque_decl) +{ + if (opaque_decl) + { + clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>((clang::Decl*)opaque_decl); + if (nd != nullptr && !llvm::isa<clang::ObjCMethodDecl>(nd)) + { + clang::MangleContext *mc = getMangleContext(); + if (mc && mc->shouldMangleCXXName(nd)) + { + llvm::SmallVector<char, 1024> buf; + llvm::raw_svector_ostream llvm_ostrm (buf); + if (llvm::isa<clang::CXXConstructorDecl>(nd)) + { + mc->mangleCXXCtor(llvm::dyn_cast<clang::CXXConstructorDecl>(nd), Ctor_Complete, llvm_ostrm); + } + else if (llvm::isa<clang::CXXDestructorDecl>(nd)) + { + mc->mangleCXXDtor(llvm::dyn_cast<clang::CXXDestructorDecl>(nd), Dtor_Complete, llvm_ostrm); + } + else + { + mc->mangleName(nd, llvm_ostrm); + } + if (buf.size() > 0) + return ConstString(buf.data(), buf.size()); + } + } + } + return ConstString(); +} + +CompilerDeclContext +ClangASTContext::DeclGetDeclContext (void *opaque_decl) +{ + if (opaque_decl) + return CompilerDeclContext(this, ((clang::Decl*)opaque_decl)->getDeclContext()); + else + return CompilerDeclContext(); +} + +CompilerType +ClangASTContext::DeclGetFunctionReturnType(void *opaque_decl) +{ + if (clang::FunctionDecl *func_decl = llvm::dyn_cast<clang::FunctionDecl>((clang::Decl*)opaque_decl)) + return CompilerType(this, func_decl->getReturnType().getAsOpaquePtr()); + if (clang::ObjCMethodDecl *objc_method = llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl*)opaque_decl)) + return CompilerType(this, objc_method->getReturnType().getAsOpaquePtr()); + else + return CompilerType(); +} + +size_t +ClangASTContext::DeclGetFunctionNumArguments(void *opaque_decl) +{ + if (clang::FunctionDecl *func_decl = llvm::dyn_cast<clang::FunctionDecl>((clang::Decl*)opaque_decl)) + return func_decl->param_size(); + if (clang::ObjCMethodDecl *objc_method = llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl*)opaque_decl)) + return objc_method->param_size(); + else + return 0; +} + +CompilerType +ClangASTContext::DeclGetFunctionArgumentType (void *opaque_decl, size_t idx) +{ + if (clang::FunctionDecl *func_decl = llvm::dyn_cast<clang::FunctionDecl>((clang::Decl*)opaque_decl)) + { + if (idx < func_decl->param_size()) + { + ParmVarDecl *var_decl = func_decl->getParamDecl(idx); + if (var_decl) + return CompilerType(this, var_decl->getOriginalType().getAsOpaquePtr()); + } + } + else if (clang::ObjCMethodDecl *objc_method = llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl*)opaque_decl)) + { + if (idx < objc_method->param_size()) + return CompilerType(this, objc_method->parameters()[idx]->getOriginalType().getAsOpaquePtr()); + } + return CompilerType(); +} + +//---------------------------------------------------------------------- +// CompilerDeclContext functions +//---------------------------------------------------------------------- + +std::vector<CompilerDecl> +ClangASTContext::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name) +{ + std::vector<CompilerDecl> found_decls; + if (opaque_decl_ctx) + { + DeclContext *root_decl_ctx = (DeclContext *)opaque_decl_ctx; + std::set<DeclContext *> searched; + std::multimap<DeclContext *, DeclContext *> search_queue; + SymbolFile *symbol_file = GetSymbolFile(); + + for (clang::DeclContext *decl_context = root_decl_ctx; decl_context != nullptr && found_decls.empty(); decl_context = decl_context->getParent()) + { + search_queue.insert(std::make_pair(decl_context, decl_context)); + + for (auto it = search_queue.find(decl_context); it != search_queue.end(); it++) + { + if (!searched.insert(it->second).second) + continue; + symbol_file->ParseDeclsForContext(CompilerDeclContext(this, it->second)); + + for (clang::Decl *child : it->second->decls()) + { + if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) + { + clang::DeclContext *from = ud->getCommonAncestor(); + if (searched.find(ud->getNominatedNamespace()) == searched.end()) + search_queue.insert(std::make_pair(from, ud->getNominatedNamespace())); + } + else if (clang::UsingDecl *ud = llvm::dyn_cast<clang::UsingDecl>(child)) + { + for (clang::UsingShadowDecl *usd : ud->shadows()) + { + clang::Decl *target = usd->getTargetDecl(); + if (clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(target)) + { + IdentifierInfo *ii = nd->getIdentifier(); + if (ii != nullptr && ii->getName().equals(name.AsCString(nullptr))) + found_decls.push_back(CompilerDecl(this, nd)); + } + } + } + else if (clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(child)) + { + IdentifierInfo *ii = nd->getIdentifier(); + if (ii != nullptr && ii->getName().equals(name.AsCString(nullptr))) + found_decls.push_back(CompilerDecl(this, nd)); + } + } } - language = eLanguageTypeObjC; + } + } + return found_decls; +} + +// Look for child_decl_ctx's lookup scope in frame_decl_ctx and its parents, +// and return the number of levels it took to find it, or LLDB_INVALID_DECL_LEVEL +// if not found. If the decl was imported via a using declaration, its name and/or +// type, if set, will be used to check that the decl found in the scope is a match. +// +// The optional name is required by languages (like C++) to handle using declarations +// like: +// +// void poo(); +// namespace ns { +// void foo(); +// void goo(); +// } +// void bar() { +// using ns::foo; +// // CountDeclLevels returns 0 for 'foo', 1 for 'poo', and +// // LLDB_INVALID_DECL_LEVEL for 'goo'. +// } +// +// The optional type is useful in the case that there's a specific overload +// that we're looking for that might otherwise be shadowed, like: +// +// void foo(int); +// namespace ns { +// void foo(); +// } +// void bar() { +// using ns::foo; +// // CountDeclLevels returns 0 for { 'foo', void() }, +// // 1 for { 'foo', void(int) }, and +// // LLDB_INVALID_DECL_LEVEL for { 'foo', void(int, int) }. +// } +// +// NOTE: Because file statics are at the TranslationUnit along with globals, a +// function at file scope will return the same level as a function at global scope. +// Ideally we'd like to treat the file scope as an additional scope just below the +// global scope. More work needs to be done to recognise that, if the decl we're +// trying to look up is static, we should compare its source file with that of the +// current scope and return a lower number for it. +uint32_t +ClangASTContext::CountDeclLevels (clang::DeclContext *frame_decl_ctx, + clang::DeclContext *child_decl_ctx, + ConstString *child_name, + CompilerType *child_type) +{ + if (frame_decl_ctx) + { + std::set<DeclContext *> searched; + std::multimap<DeclContext *, DeclContext *> search_queue; + SymbolFile *symbol_file = GetSymbolFile(); + + // Get the lookup scope for the decl we're trying to find. + clang::DeclContext *parent_decl_ctx = child_decl_ctx->getParent(); + + // Look for it in our scope's decl context and its parents. + uint32_t level = 0; + for (clang::DeclContext *decl_ctx = frame_decl_ctx; decl_ctx != nullptr; decl_ctx = decl_ctx->getParent()) + { + if (!decl_ctx->isLookupContext()) + continue; + if (decl_ctx == parent_decl_ctx) + // Found it! + return level; + search_queue.insert(std::make_pair(decl_ctx, decl_ctx)); + for (auto it = search_queue.find(decl_ctx); it != search_queue.end(); it++) + { + if (searched.find(it->second) != searched.end()) + continue; + searched.insert(it->second); + symbol_file->ParseDeclsForContext(CompilerDeclContext(this, it->second)); + + for (clang::Decl *child : it->second->decls()) + { + if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) + { + clang::DeclContext *ns = ud->getNominatedNamespace(); + if (ns == parent_decl_ctx) + // Found it! + return level; + clang::DeclContext *from = ud->getCommonAncestor(); + if (searched.find(ns) == searched.end()) + search_queue.insert(std::make_pair(from, ns)); + } + else if (child_name) + { + if (clang::UsingDecl *ud = llvm::dyn_cast<clang::UsingDecl>(child)) + { + for (clang::UsingShadowDecl *usd : ud->shadows()) + { + clang::Decl *target = usd->getTargetDecl(); + clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(target); + if (!nd) + continue; + // Check names. + IdentifierInfo *ii = nd->getIdentifier(); + if (ii == nullptr || !ii->getName().equals(child_name->AsCString(nullptr))) + continue; + // Check types, if one was provided. + if (child_type) + { + CompilerType clang_type = ClangASTContext::GetTypeForDecl(nd); + if (!AreTypesSame(clang_type, *child_type, /*ignore_qualifiers=*/true)) + continue; + } + // Found it! + return level; + } + } + } + } + } + ++level; + } + } + return LLDB_INVALID_DECL_LEVEL; +} + +bool +ClangASTContext::DeclContextIsStructUnionOrClass (void *opaque_decl_ctx) +{ + if (opaque_decl_ctx) + return ((clang::DeclContext *)opaque_decl_ctx)->isRecord(); + else + return false; +} + +ConstString +ClangASTContext::DeclContextGetName (void *opaque_decl_ctx) +{ + if (opaque_decl_ctx) + { + clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx); + if (named_decl) + return ConstString(named_decl->getName()); + } + return ConstString(); +} + +bool +ClangASTContext::DeclContextIsClassMethod (void *opaque_decl_ctx, + lldb::LanguageType *language_ptr, + bool *is_instance_method_ptr, + ConstString *language_object_name_ptr) +{ + if (opaque_decl_ctx) + { + clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; + if (ObjCMethodDecl *objc_method = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx)) + { + if (is_instance_method_ptr) + *is_instance_method_ptr = objc_method->isInstanceMethod(); + if (language_ptr) + *language_ptr = eLanguageTypeObjC; + if (language_object_name_ptr) + language_object_name_ptr->SetCString("self"); + return true; + } + else if (CXXMethodDecl *cxx_method = llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx)) + { + if (is_instance_method_ptr) + *is_instance_method_ptr = cxx_method->isInstance(); + if (language_ptr) + *language_ptr = eLanguageTypeC_plus_plus; + if (language_object_name_ptr) + language_object_name_ptr->SetCString("this"); return true; } else if (clang::FunctionDecl *function_decl = llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) @@ -2195,13 +10003,129 @@ ClangASTContext::GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx, ClangASTMetadata *metadata = GetMetadata (&decl_ctx->getParentASTContext(), function_decl); if (metadata && metadata->HasObjectPtr()) { - language_object_name.SetCString (metadata->GetObjectPtrName()); - language = eLanguageTypeObjC; - is_instance_method = true; + if (is_instance_method_ptr) + *is_instance_method_ptr = true; + if (language_ptr) + *language_ptr = eLanguageTypeObjC; + if (language_object_name_ptr) + language_object_name_ptr->SetCString (metadata->GetObjectPtrName()); + return true; } - return true; } } return false; } +clang::DeclContext * +ClangASTContext::DeclContextGetAsDeclContext (const CompilerDeclContext &dc) +{ + if (dc.IsClang()) + return (clang::DeclContext *)dc.GetOpaqueDeclContext(); + return nullptr; +} + + +ObjCMethodDecl * +ClangASTContext::DeclContextGetAsObjCMethodDecl (const CompilerDeclContext &dc) +{ + if (dc.IsClang()) + return llvm::dyn_cast<clang::ObjCMethodDecl>((clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +CXXMethodDecl * +ClangASTContext::DeclContextGetAsCXXMethodDecl (const CompilerDeclContext &dc) +{ + if (dc.IsClang()) + return llvm::dyn_cast<clang::CXXMethodDecl>((clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +clang::FunctionDecl * +ClangASTContext::DeclContextGetAsFunctionDecl (const CompilerDeclContext &dc) +{ + if (dc.IsClang()) + return llvm::dyn_cast<clang::FunctionDecl>((clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +clang::NamespaceDecl * +ClangASTContext::DeclContextGetAsNamespaceDecl (const CompilerDeclContext &dc) +{ + if (dc.IsClang()) + return llvm::dyn_cast<clang::NamespaceDecl>((clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +ClangASTMetadata * +ClangASTContext::DeclContextGetMetaData (const CompilerDeclContext &dc, const void *object) +{ + clang::ASTContext *ast = DeclContextGetClangASTContext (dc); + if (ast) + return ClangASTContext::GetMetadata (ast, object); + return nullptr; +} + +clang::ASTContext * +ClangASTContext::DeclContextGetClangASTContext (const CompilerDeclContext &dc) +{ + ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(dc.GetTypeSystem()); + if (ast) + return ast->getASTContext(); + return nullptr; +} + +ClangASTContextForExpressions::ClangASTContextForExpressions (Target &target) : + ClangASTContext (target.GetArchitecture().GetTriple().getTriple().c_str()), + m_target_wp(target.shared_from_this()), + m_persistent_variables (new ClangPersistentVariables) +{ +} + +UserExpression * +ClangASTContextForExpressions::GetUserExpression (const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options) +{ + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + return new ClangUserExpression(*target_sp.get(), expr, expr_prefix, language, desired_type, options); +} + +FunctionCaller * +ClangASTContextForExpressions::GetFunctionCaller (const CompilerType &return_type, + const Address& function_address, + const ValueList &arg_value_list, + const char *name) +{ + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + Process *process = target_sp->GetProcessSP().get(); + if (!process) + return nullptr; + + return new ClangFunctionCaller (*process, return_type, function_address, arg_value_list, name); +} + +UtilityFunction * +ClangASTContextForExpressions::GetUtilityFunction (const char *text, + const char *name) +{ + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + return new ClangUtilityFunction(*target_sp.get(), text, name); +} + +PersistentExpressionState * +ClangASTContextForExpressions::GetPersistentExpressionState () +{ + return m_persistent_variables.get(); +} |