diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /lldb/source/Symbol | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'lldb/source/Symbol')
38 files changed, 244 insertions, 11139 deletions
diff --git a/lldb/source/Symbol/ArmUnwindInfo.cpp b/lldb/source/Symbol/ArmUnwindInfo.cpp index fdf4e30b2db5..f2887035e5cf 100644 --- a/lldb/source/Symbol/ArmUnwindInfo.cpp +++ b/lldb/source/Symbol/ArmUnwindInfo.cpp @@ -1,4 +1,4 @@ -//===-- ArmUnwindInfo.cpp ---------------------------------------*- C++ -*-===// +//===-- ArmUnwindInfo.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -29,7 +29,7 @@ using namespace lldb; using namespace lldb_private; -// Converts a prel31 avlue to lldb::addr_t with sign extension +// Converts a prel31 value to lldb::addr_t with sign extension static addr_t Prel31ToAddr(uint32_t prel31) { addr_t res = prel31; if (prel31 & (1 << 30)) diff --git a/lldb/source/Symbol/Block.cpp b/lldb/source/Symbol/Block.cpp index bf380064200a..afcdf3e21e19 100644 --- a/lldb/source/Symbol/Block.cpp +++ b/lldb/source/Symbol/Block.cpp @@ -1,4 +1,4 @@ -//===-- Block.cpp -----------------------------------------------*- C++ -*-===// +//===-- Block.cpp ---------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp deleted file mode 100644 index ac3bce179d9e..000000000000 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ /dev/null @@ -1,9298 +0,0 @@ -//===-- ClangASTContext.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Symbol/ClangASTContext.h" - -#include "llvm/Support/FormatAdapters.h" -#include "llvm/Support/FormatVariadic.h" - -#include <mutex> -#include <string> -#include <vector> - -#include "clang/AST/ASTContext.h" -#include "clang/AST/ASTImporter.h" -#include "clang/AST/Attr.h" -#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" -#include "clang/Basic/FileSystemOptions.h" -#include "clang/Basic/LangStandard.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" -#include "clang/Frontend/FrontendOptions.h" -#include "clang/Sema/Sema.h" - -#include "llvm/Support/Signals.h" -#include "llvm/Support/Threading.h" - -#include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h" -#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" -#include "Plugins/ExpressionParser/Clang/ClangUserExpression.h" -#include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/Flags.h" - -#include "lldb/Core/DumpDataExtractor.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" -#include "lldb/Core/ThreadSafeDenseMap.h" -#include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" -#include "lldb/Symbol/ClangUtil.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/SymbolFile.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Language.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegularExpression.h" -#include "lldb/Utility/Scalar.h" - -#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" -#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" -#include "Plugins/SymbolFile/PDB/PDBASTParser.h" - -#include <stdio.h> - -#include <mutex> - -using namespace lldb; -using namespace lldb_private; -using namespace clang; -using llvm::StringSwitch; - -namespace { -#ifdef LLDB_CONFIGURATION_DEBUG -static void VerifyDecl(clang::Decl *decl) { - assert(decl && "VerifyDecl called with nullptr?"); - decl->getAccess(); -} -#endif - -static inline bool -ClangASTContextSupportsLanguage(lldb::LanguageType language) { - return language == eLanguageTypeUnknown || // Clang is the default type system - lldb_private::Language::LanguageIsC(language) || - lldb_private::Language::LanguageIsCPlusPlus(language) || - lldb_private::Language::LanguageIsObjC(language) || - lldb_private::Language::LanguageIsPascal(language) || - // Use Clang for Rust until there is a proper language plugin for it - language == eLanguageTypeRust || - language == eLanguageTypeExtRenderScript || - // Use Clang for D until there is a proper language plugin for it - language == eLanguageTypeD || - // Open Dylan compiler debug info is designed to be Clang-compatible - language == eLanguageTypeDylan; -} - -// Checks whether m1 is an overload of m2 (as opposed to an override). This is -// called by addOverridesForMethod to distinguish overrides (which share a -// vtable entry) from overloads (which require distinct entries). -bool isOverload(clang::CXXMethodDecl *m1, clang::CXXMethodDecl *m2) { - // FIXME: This should detect covariant return types, but currently doesn't. - lldbassert(&m1->getASTContext() == &m2->getASTContext() && - "Methods should have the same AST context"); - clang::ASTContext &context = m1->getASTContext(); - - const auto *m1Type = llvm::cast<clang::FunctionProtoType>( - context.getCanonicalType(m1->getType())); - - const auto *m2Type = llvm::cast<clang::FunctionProtoType>( - context.getCanonicalType(m2->getType())); - - auto compareArgTypes = [&context](const clang::QualType &m1p, - const clang::QualType &m2p) { - return context.hasSameType(m1p.getUnqualifiedType(), - m2p.getUnqualifiedType()); - }; - - // FIXME: In C++14 and later, we can just pass m2Type->param_type_end() - // as a fourth parameter to std::equal(). - return (m1->getNumParams() != m2->getNumParams()) || - !std::equal(m1Type->param_type_begin(), m1Type->param_type_end(), - m2Type->param_type_begin(), compareArgTypes); -} - -// If decl is a virtual method, walk the base classes looking for methods that -// decl overrides. This table of overridden methods is used by IRGen to -// determine the vtable layout for decl's parent class. -void addOverridesForMethod(clang::CXXMethodDecl *decl) { - if (!decl->isVirtual()) - return; - - clang::CXXBasePaths paths; - - auto find_overridden_methods = - [decl](const clang::CXXBaseSpecifier *specifier, - clang::CXXBasePath &path) { - if (auto *base_record = llvm::dyn_cast<clang::CXXRecordDecl>( - specifier->getType()->getAs<clang::RecordType>()->getDecl())) { - - clang::DeclarationName name = decl->getDeclName(); - - // If this is a destructor, check whether the base class destructor is - // virtual. - if (name.getNameKind() == clang::DeclarationName::CXXDestructorName) - if (auto *baseDtorDecl = base_record->getDestructor()) { - if (baseDtorDecl->isVirtual()) { - path.Decls = baseDtorDecl; - return true; - } else - return false; - } - - // Otherwise, search for name in the base class. - for (path.Decls = base_record->lookup(name); !path.Decls.empty(); - path.Decls = path.Decls.slice(1)) { - if (auto *method_decl = - llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front())) - if (method_decl->isVirtual() && !isOverload(decl, method_decl)) { - path.Decls = method_decl; - return true; - } - } - } - - return false; - }; - - if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) { - for (auto *overridden_decl : paths.found_decls()) - decl->addOverriddenMethod( - llvm::cast<clang::CXXMethodDecl>(overridden_decl)); - } -} -} - -static lldb::addr_t GetVTableAddress(Process &process, - VTableContextBase &vtable_ctx, - ValueObject &valobj, - const ASTRecordLayout &record_layout) { - // Retrieve type info - CompilerType pointee_type; - CompilerType this_type(valobj.GetCompilerType()); - uint32_t type_info = this_type.GetTypeInfo(&pointee_type); - if (!type_info) - return LLDB_INVALID_ADDRESS; - - // Check if it's a pointer or reference - bool ptr_or_ref = false; - if (type_info & (eTypeIsPointer | eTypeIsReference)) { - ptr_or_ref = true; - type_info = pointee_type.GetTypeInfo(); - } - - // We process only C++ classes - const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus; - if ((type_info & cpp_class) != cpp_class) - return LLDB_INVALID_ADDRESS; - - // Calculate offset to VTable pointer - lldb::offset_t vbtable_ptr_offset = - vtable_ctx.isMicrosoft() ? record_layout.getVBPtrOffset().getQuantity() - : 0; - - if (ptr_or_ref) { - // We have a pointer / ref to object, so read - // VTable pointer from process memory - - if (valobj.GetAddressTypeOfChildren() != eAddressTypeLoad) - return LLDB_INVALID_ADDRESS; - - auto vbtable_ptr_addr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - if (vbtable_ptr_addr == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - vbtable_ptr_addr += vbtable_ptr_offset; - - Status err; - return process.ReadPointerFromMemory(vbtable_ptr_addr, err); - } - - // We have an object already read from process memory, - // so just extract VTable pointer from it - - DataExtractor data; - Status err; - auto size = valobj.GetData(data, err); - if (err.Fail() || vbtable_ptr_offset + data.GetAddressByteSize() > size) - return LLDB_INVALID_ADDRESS; - - return data.GetPointer(&vbtable_ptr_offset); -} - -static int64_t ReadVBaseOffsetFromVTable(Process &process, - VTableContextBase &vtable_ctx, - lldb::addr_t vtable_ptr, - const CXXRecordDecl *cxx_record_decl, - const CXXRecordDecl *base_class_decl) { - if (vtable_ctx.isMicrosoft()) { - clang::MicrosoftVTableContext &msoft_vtable_ctx = - static_cast<clang::MicrosoftVTableContext &>(vtable_ctx); - - // 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 = vtable_ptr + vbtable_index * 4; - Status err; - return process.ReadSignedIntegerFromMemory(base_offset_addr, 4, INT64_MAX, - err); - } - - clang::ItaniumVTableContext &itanium_vtable_ctx = - static_cast<clang::ItaniumVTableContext &>(vtable_ctx); - - 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_size = process.GetAddressByteSize(); - Status err; - return process.ReadSignedIntegerFromMemory(base_offset_addr, base_offset_size, - INT64_MAX, err); -} - -static bool GetVBaseBitOffset(VTableContextBase &vtable_ctx, - ValueObject &valobj, - const ASTRecordLayout &record_layout, - const CXXRecordDecl *cxx_record_decl, - const CXXRecordDecl *base_class_decl, - int32_t &bit_offset) { - ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (!process) - return false; - - lldb::addr_t vtable_ptr = - GetVTableAddress(*process, vtable_ctx, valobj, record_layout); - if (vtable_ptr == LLDB_INVALID_ADDRESS) - return false; - - auto base_offset = ReadVBaseOffsetFromVTable( - *process, vtable_ctx, vtable_ptr, cxx_record_decl, base_class_decl); - if (base_offset == INT64_MAX) - return false; - - bit_offset = base_offset * 8; - - return true; -} - -typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, ClangASTContext *> - ClangASTMap; - -static ClangASTMap &GetASTMap() { - static ClangASTMap *g_map_ptr = nullptr; - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { - g_map_ptr = new ClangASTMap(); // leaked on purpose to avoid spins - }); - return *g_map_ptr; -} - -char ClangASTContext::ID; - -bool ClangASTContext::IsOperator(llvm::StringRef name, - clang::OverloadedOperatorKind &op_kind) { - // All operators have to start with "operator". - if (!name.consume_front("operator")) - return false; - - // Remember if there was a space after "operator". This is necessary to - // check for collisions with strangely named functions like "operatorint()". - bool space_after_operator = name.consume_front(" "); - - op_kind = StringSwitch<clang::OverloadedOperatorKind>(name) - .Case("+", clang::OO_Plus) - .Case("+=", clang::OO_PlusEqual) - .Case("++", clang::OO_PlusPlus) - .Case("-", clang::OO_Minus) - .Case("-=", clang::OO_MinusEqual) - .Case("--", clang::OO_MinusMinus) - .Case("->", clang::OO_Arrow) - .Case("->*", clang::OO_ArrowStar) - .Case("*", clang::OO_Star) - .Case("*=", clang::OO_StarEqual) - .Case("/", clang::OO_Slash) - .Case("/=", clang::OO_SlashEqual) - .Case("%", clang::OO_Percent) - .Case("%=", clang::OO_PercentEqual) - .Case("^", clang::OO_Caret) - .Case("^=", clang::OO_CaretEqual) - .Case("&", clang::OO_Amp) - .Case("&=", clang::OO_AmpEqual) - .Case("&&", clang::OO_AmpAmp) - .Case("|", clang::OO_Pipe) - .Case("|=", clang::OO_PipeEqual) - .Case("||", clang::OO_PipePipe) - .Case("~", clang::OO_Tilde) - .Case("!", clang::OO_Exclaim) - .Case("!=", clang::OO_ExclaimEqual) - .Case("=", clang::OO_Equal) - .Case("==", clang::OO_EqualEqual) - .Case("<", clang::OO_Less) - .Case("<<", clang::OO_LessLess) - .Case("<<=", clang::OO_LessLessEqual) - .Case("<=", clang::OO_LessEqual) - .Case(">", clang::OO_Greater) - .Case(">>", clang::OO_GreaterGreater) - .Case(">>=", clang::OO_GreaterGreaterEqual) - .Case(">=", clang::OO_GreaterEqual) - .Case("()", clang::OO_Call) - .Case("[]", clang::OO_Subscript) - .Case(",", clang::OO_Comma) - .Default(clang::NUM_OVERLOADED_OPERATORS); - - // We found a fitting operator, so we can exit now. - if (op_kind != clang::NUM_OVERLOADED_OPERATORS) - return true; - - // After the "operator " or "operator" part is something unknown. This means - // it's either one of the named operators (new/delete), a conversion operator - // (e.g. operator bool) or a function which name starts with "operator" - // (e.g. void operatorbool). - - // If it's a function that starts with operator it can't have a space after - // "operator" because identifiers can't contain spaces. - // E.g. "operator int" (conversion operator) - // vs. "operatorint" (function with colliding name). - if (!space_after_operator) - return false; // not an operator. - - // Now the operator is either one of the named operators or a conversion - // operator. - op_kind = StringSwitch<clang::OverloadedOperatorKind>(name) - .Case("new", clang::OO_New) - .Case("new[]", clang::OO_Array_New) - .Case("delete", clang::OO_Delete) - .Case("delete[]", clang::OO_Array_Delete) - // conversion operators hit this case. - .Default(clang::NUM_OVERLOADED_OPERATORS); - - return true; -} - -clang::AccessSpecifier -ClangASTContext::ConvertAccessTypeToAccessSpecifier(AccessType access) { - switch (access) { - default: - break; - case eAccessNone: - return AS_none; - case eAccessPublic: - return AS_public; - case eAccessPrivate: - return AS_private; - case eAccessProtected: - return AS_protected; - } - return AS_none; -} - -static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { - // FIXME: Cleanup per-file based stuff. - - // Set some properties which depend solely on the input kind; it would be - // nice to move these to the language standard, and have the driver resolve - // the input kind + language standard. - if (IK.getLanguage() == clang::Language::Asm) { - Opts.AsmPreprocessor = 1; - } else if (IK.isObjectiveC()) { - Opts.ObjC = 1; - } - - LangStandard::Kind LangStd = LangStandard::lang_unspecified; - - if (LangStd == LangStandard::lang_unspecified) { - // Based on the base language, pick one. - switch (IK.getLanguage()) { - case clang::Language::Unknown: - case clang::Language::LLVM_IR: - case clang::Language::RenderScript: - llvm_unreachable("Invalid input kind!"); - case clang::Language::OpenCL: - LangStd = LangStandard::lang_opencl10; - break; - case clang::Language::CUDA: - LangStd = LangStandard::lang_cuda; - break; - case clang::Language::Asm: - case clang::Language::C: - case clang::Language::ObjC: - LangStd = LangStandard::lang_gnu99; - break; - case clang::Language::CXX: - case clang::Language::ObjCXX: - LangStd = LangStandard::lang_gnucxx98; - break; - case clang::Language::HIP: - LangStd = LangStandard::lang_hip; - break; - } - } - - const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); - Opts.LineComment = Std.hasLineComments(); - Opts.C99 = Std.isC99(); - Opts.CPlusPlus = Std.isCPlusPlus(); - Opts.CPlusPlus11 = Std.isCPlusPlus11(); - Opts.Digraphs = Std.hasDigraphs(); - Opts.GNUMode = Std.isGNUMode(); - Opts.GNUInline = !Std.isC99(); - Opts.HexFloats = Std.hasHexFloats(); - Opts.ImplicitInt = Std.hasImplicitInt(); - - Opts.WChar = true; - - // OpenCL has some additional defaults. - if (LangStd == LangStandard::lang_opencl10) { - Opts.OpenCL = 1; - Opts.AltiVec = 1; - Opts.CXXOperatorNames = 1; - Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::All); - } - - // OpenCL and C++ both have bool, true, false keywords. - Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; - - Opts.setValueVisibilityMode(DefaultVisibility); - - // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs is - // specified, or -std is set to a conforming mode. - Opts.Trigraphs = !Opts.GNUMode; - Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault(); - Opts.OptimizeSize = 0; - - // FIXME: Eliminate this dependency. - // unsigned Opt = - // Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags); - // Opts.Optimize = Opt != 0; - unsigned Opt = 0; - - // This is the __NO_INLINE__ define, which just depends on things like the - // optimization level and -fno-inline, not actually whether the backend has - // inlining enabled. - // - // FIXME: This is affected by other options (-fno-inline). - Opts.NoInlineDefine = !Opt; -} - -ClangASTContext::ClangASTContext(llvm::Triple target_triple) { - if (!target_triple.str().empty()) - SetTargetTriple(target_triple.str()); - // The caller didn't pass an ASTContext so create a new one for this - // ClangASTContext. - CreateASTContext(); -} - -ClangASTContext::ClangASTContext(ASTContext &existing_ctxt) { - SetTargetTriple(existing_ctxt.getTargetInfo().getTriple().str()); - - m_ast_up.reset(&existing_ctxt); - GetASTMap().Insert(&existing_ctxt, this); -} - -// Destructor -ClangASTContext::~ClangASTContext() { Finalize(); } - -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)) - return lldb::TypeSystemSP(); - ArchSpec arch; - if (module) - arch = module->GetArchitecture(); - else if (target) - arch = target->GetArchitecture(); - - if (!arch.IsValid()) - return lldb::TypeSystemSP(); - - llvm::Triple triple = arch.GetTriple(); - // 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 (triple.getVendor() == llvm::Triple::Apple && - triple.getOS() == llvm::Triple::UnknownOS) { - if (triple.getArch() == llvm::Triple::arm || - triple.getArch() == llvm::Triple::aarch64 || - triple.getArch() == llvm::Triple::aarch64_32 || - triple.getArch() == llvm::Triple::thumb) { - triple.setOS(llvm::Triple::IOS); - } else { - triple.setOS(llvm::Triple::MacOSX); - } - } - - if (module) - return std::make_shared<ClangASTContext>(triple); - else if (target && target->IsValid()) - return std::make_shared<ClangASTContextForExpressions>(*target, triple); - return lldb::TypeSystemSP(); -} - -LanguageSet ClangASTContext::GetSupportedLanguagesForTypes() { - LanguageSet languages; - languages.Insert(lldb::eLanguageTypeC89); - languages.Insert(lldb::eLanguageTypeC); - languages.Insert(lldb::eLanguageTypeC11); - languages.Insert(lldb::eLanguageTypeC_plus_plus); - languages.Insert(lldb::eLanguageTypeC99); - languages.Insert(lldb::eLanguageTypeObjC); - languages.Insert(lldb::eLanguageTypeObjC_plus_plus); - languages.Insert(lldb::eLanguageTypeC_plus_plus_03); - languages.Insert(lldb::eLanguageTypeC_plus_plus_11); - languages.Insert(lldb::eLanguageTypeC11); - languages.Insert(lldb::eLanguageTypeC_plus_plus_14); - return languages; -} - -LanguageSet ClangASTContext::GetSupportedLanguagesForExpressions() { - LanguageSet languages; - languages.Insert(lldb::eLanguageTypeC_plus_plus); - languages.Insert(lldb::eLanguageTypeObjC_plus_plus); - languages.Insert(lldb::eLanguageTypeC_plus_plus_03); - languages.Insert(lldb::eLanguageTypeC_plus_plus_11); - languages.Insert(lldb::eLanguageTypeC_plus_plus_14); - return languages; -} - -void ClangASTContext::Initialize() { - PluginManager::RegisterPlugin( - GetPluginNameStatic(), "clang base AST context plug-in", CreateInstance, - GetSupportedLanguagesForTypes(), GetSupportedLanguagesForExpressions()); -} - -void ClangASTContext::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -void ClangASTContext::Finalize() { - assert(m_ast_up); - GetASTMap().Erase(m_ast_up.get()); - if (!m_ast_owned) - m_ast_up.release(); - - m_builtins_up.reset(); - m_selector_table_up.reset(); - m_identifier_table_up.reset(); - m_target_info_up.reset(); - m_target_options_rp.reset(); - m_diagnostics_engine_up.reset(); - m_source_manager_up.reset(); - m_language_options_up.reset(); -} - -void ClangASTContext::setSema(Sema *s) { - // Ensure that the new sema actually belongs to our ASTContext. - assert(s == nullptr || &s->getASTContext() == m_ast_up.get()); - m_sema = s; -} - -const char *ClangASTContext::GetTargetTriple() { - return m_target_triple.c_str(); -} - -void ClangASTContext::SetTargetTriple(llvm::StringRef target_triple) { - m_target_triple = target_triple.str(); -} - -void ClangASTContext::SetExternalSource( - llvm::IntrusiveRefCntPtr<ExternalASTSource> &ast_source_up) { - ASTContext &ast = getASTContext(); - ast.setExternalSource(ast_source_up); - ast.getTranslationUnitDecl()->setHasExternalLexicalStorage(true); -} - -ASTContext &ClangASTContext::getASTContext() { - assert(m_ast_up); - return *m_ast_up; -} - -class NullDiagnosticConsumer : public DiagnosticConsumer { -public: - NullDiagnosticConsumer() { - m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - } - - void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const clang::Diagnostic &info) override { - if (m_log) { - llvm::SmallVector<char, 32> diag_str(10); - info.FormatDiagnostic(diag_str); - diag_str.push_back('\0'); - LLDB_LOGF(m_log, "Compiler diagnostic: %s\n", diag_str.data()); - } - } - - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - return new NullDiagnosticConsumer(); - } - -private: - Log *m_log; -}; - -void ClangASTContext::CreateASTContext() { - assert(!m_ast_up); - m_ast_owned = true; - - m_language_options_up.reset(new LangOptions()); - ParseLangArgs(*m_language_options_up, clang::Language::ObjCXX, - GetTargetTriple()); - - m_identifier_table_up.reset( - new IdentifierTable(*m_language_options_up, nullptr)); - m_builtins_up.reset(new Builtin::Context()); - - m_selector_table_up.reset(new SelectorTable()); - - clang::FileSystemOptions file_system_options; - m_file_manager_up.reset(new clang::FileManager( - file_system_options, FileSystem::Instance().GetVirtualFileSystem())); - - llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs()); - m_diagnostics_engine_up.reset( - new DiagnosticsEngine(diag_id_sp, new DiagnosticOptions())); - - m_source_manager_up.reset( - new clang::SourceManager(*m_diagnostics_engine_up, *m_file_manager_up)); - m_ast_up.reset(new ASTContext(*m_language_options_up, *m_source_manager_up, - *m_identifier_table_up, *m_selector_table_up, - *m_builtins_up)); - - m_diagnostic_consumer_up.reset(new NullDiagnosticConsumer); - m_ast_up->getDiagnostics().setClient(m_diagnostic_consumer_up.get(), false); - - // This can be NULL if we don't know anything about the architecture or if - // the target for an architecture isn't enabled in the llvm/clang that we - // built - TargetInfo *target_info = getTargetInfo(); - if (target_info) - m_ast_up->InitBuiltinTypes(*target_info); - - GetASTMap().Insert(m_ast_up.get(), this); - - llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_up( - new ClangExternalASTSourceCallbacks(*this)); - SetExternalSource(ast_source_up); -} - -ClangASTContext *ClangASTContext::GetASTContext(clang::ASTContext *ast) { - ClangASTContext *clang_ast = GetASTMap().Lookup(ast); - return clang_ast; -} - -clang::MangleContext *ClangASTContext::getMangleContext() { - if (m_mangle_ctx_up == nullptr) - m_mangle_ctx_up.reset(getASTContext().createMangleContext()); - return m_mangle_ctx_up.get(); -} - -std::shared_ptr<clang::TargetOptions> &ClangASTContext::getTargetOptions() { - if (m_target_options_rp == nullptr && !m_target_triple.empty()) { - m_target_options_rp = std::make_shared<clang::TargetOptions>(); - if (m_target_options_rp != nullptr) - m_target_options_rp->Triple = m_target_triple; - } - return m_target_options_rp; -} - -TargetInfo *ClangASTContext::getTargetInfo() { - // target_triple should be something like "x86_64-apple-macosx" - if (m_target_info_up == nullptr && !m_target_triple.empty()) - m_target_info_up.reset(TargetInfo::CreateTargetInfo( - getASTContext().getDiagnostics(), getTargetOptions())); - return m_target_info_up.get(); -} - -#pragma mark Basic Types - -static inline bool QualTypeMatchesBitSize(const uint64_t bit_size, - ASTContext &ast, QualType qual_type) { - uint64_t qual_type_bit_size = ast.getTypeSize(qual_type); - return qual_type_bit_size == bit_size; -} - -CompilerType -ClangASTContext::GetBuiltinTypeForEncodingAndBitSize(Encoding encoding, - size_t bit_size) { - ASTContext &ast = getASTContext(); - switch (encoding) { - case eEncodingInvalid: - if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy)) - return GetType(ast.VoidPtrTy); - break; - - case eEncodingUint: - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) - return GetType(ast.UnsignedCharTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) - return GetType(ast.UnsignedShortTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) - return GetType(ast.UnsignedIntTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy)) - return GetType(ast.UnsignedLongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy)) - return GetType(ast.UnsignedLongLongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty)) - return GetType(ast.UnsignedInt128Ty); - break; - - case eEncodingSint: - if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy)) - return GetType(ast.SignedCharTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy)) - return GetType(ast.ShortTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy)) - return GetType(ast.IntTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy)) - return GetType(ast.LongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy)) - return GetType(ast.LongLongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty)) - return GetType(ast.Int128Ty); - break; - - case eEncodingIEEE754: - if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) - return GetType(ast.FloatTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy)) - return GetType(ast.DoubleTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) - return GetType(ast.LongDoubleTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) - return GetType(ast.HalfTy); - break; - - case eEncodingVector: - // Sanity check that bit_size is a multiple of 8's. - if (bit_size && !(bit_size & 0x7u)) - return GetType(ast.getExtVectorType(ast.UnsignedCharTy, bit_size / 8)); - break; - } - - return CompilerType(); -} - -lldb::BasicType -ClangASTContext::GetBasicTypeEnumeration(ConstString name) { - if (name) { - typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap; - static TypeNameToBasicTypeMap g_type_map; - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { - // "void" - g_type_map.Append(ConstString("void"), eBasicTypeVoid); - - // "char" - g_type_map.Append(ConstString("char"), eBasicTypeChar); - g_type_map.Append(ConstString("signed char"), eBasicTypeSignedChar); - g_type_map.Append(ConstString("unsigned char"), eBasicTypeUnsignedChar); - g_type_map.Append(ConstString("wchar_t"), eBasicTypeWChar); - g_type_map.Append(ConstString("signed wchar_t"), eBasicTypeSignedWChar); - g_type_map.Append(ConstString("unsigned wchar_t"), - eBasicTypeUnsignedWChar); - // "short" - g_type_map.Append(ConstString("short"), eBasicTypeShort); - g_type_map.Append(ConstString("short int"), eBasicTypeShort); - g_type_map.Append(ConstString("unsigned short"), eBasicTypeUnsignedShort); - g_type_map.Append(ConstString("unsigned short int"), - eBasicTypeUnsignedShort); - - // "int" - g_type_map.Append(ConstString("int"), eBasicTypeInt); - g_type_map.Append(ConstString("signed int"), eBasicTypeInt); - g_type_map.Append(ConstString("unsigned int"), eBasicTypeUnsignedInt); - g_type_map.Append(ConstString("unsigned"), eBasicTypeUnsignedInt); - - // "long" - g_type_map.Append(ConstString("long"), eBasicTypeLong); - g_type_map.Append(ConstString("long int"), eBasicTypeLong); - g_type_map.Append(ConstString("unsigned long"), eBasicTypeUnsignedLong); - g_type_map.Append(ConstString("unsigned long int"), - eBasicTypeUnsignedLong); - - // "long long" - g_type_map.Append(ConstString("long long"), eBasicTypeLongLong); - g_type_map.Append(ConstString("long long int"), eBasicTypeLongLong); - g_type_map.Append(ConstString("unsigned long long"), - eBasicTypeUnsignedLongLong); - g_type_map.Append(ConstString("unsigned long long int"), - eBasicTypeUnsignedLongLong); - - // "int128" - g_type_map.Append(ConstString("__int128_t"), eBasicTypeInt128); - g_type_map.Append(ConstString("__uint128_t"), eBasicTypeUnsignedInt128); - - // Miscellaneous - g_type_map.Append(ConstString("bool"), eBasicTypeBool); - g_type_map.Append(ConstString("float"), eBasicTypeFloat); - g_type_map.Append(ConstString("double"), eBasicTypeDouble); - g_type_map.Append(ConstString("long double"), eBasicTypeLongDouble); - g_type_map.Append(ConstString("id"), eBasicTypeObjCID); - g_type_map.Append(ConstString("SEL"), eBasicTypeObjCSel); - g_type_map.Append(ConstString("nullptr"), eBasicTypeNullPtr); - g_type_map.Sort(); - }); - - return g_type_map.Find(name, eBasicTypeInvalid); - } - return eBasicTypeInvalid; -} - -uint32_t ClangASTContext::GetPointerByteSize() { - if (m_pointer_byte_size == 0) - if (auto size = GetBasicType(lldb::eBasicTypeVoid) - .GetPointerType() - .GetByteSize(nullptr)) - m_pointer_byte_size = *size; - return m_pointer_byte_size; -} - -CompilerType ClangASTContext::GetBasicType(lldb::BasicType basic_type) { - clang::ASTContext &ast = getASTContext(); - - lldb::opaque_compiler_type_t clang_type = - GetOpaqueCompilerType(&ast, basic_type); - - if (clang_type) - return CompilerType(this, clang_type); - return CompilerType(); -} - -CompilerType ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize( - llvm::StringRef type_name, uint32_t dw_ate, uint32_t bit_size) { - ASTContext &ast = getASTContext(); - - switch (dw_ate) { - default: - break; - - case DW_ATE_address: - if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy)) - return GetType(ast.VoidPtrTy); - break; - - case DW_ATE_boolean: - if (QualTypeMatchesBitSize(bit_size, ast, ast.BoolTy)) - return GetType(ast.BoolTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) - return GetType(ast.UnsignedCharTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) - return GetType(ast.UnsignedShortTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) - return GetType(ast.UnsignedIntTy); - break; - - case DW_ATE_lo_user: - // This has been seen to mean DW_AT_complex_integer - if (type_name.contains("complex")) { - CompilerType complex_int_clang_type = - GetBuiltinTypeForDWARFEncodingAndBitSize("int", DW_ATE_signed, - bit_size / 2); - return GetType( - ast.getComplexType(ClangUtil::GetQualType(complex_int_clang_type))); - } - break; - - case DW_ATE_complex_float: - if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatComplexTy)) - return GetType(ast.FloatComplexTy); - else if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleComplexTy)) - return GetType(ast.DoubleComplexTy); - else if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleComplexTy)) - return GetType(ast.LongDoubleComplexTy); - else { - CompilerType complex_float_clang_type = - GetBuiltinTypeForDWARFEncodingAndBitSize("float", DW_ATE_float, - bit_size / 2); - return GetType( - ast.getComplexType(ClangUtil::GetQualType(complex_float_clang_type))); - } - break; - - case DW_ATE_float: - if (type_name == "float" && - QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) - return GetType(ast.FloatTy); - if (type_name == "double" && - QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy)) - return GetType(ast.DoubleTy); - if (type_name == "long double" && - QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) - return GetType(ast.LongDoubleTy); - // Fall back to not requiring a name match - if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) - return GetType(ast.FloatTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy)) - return GetType(ast.DoubleTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) - return GetType(ast.LongDoubleTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) - return GetType(ast.HalfTy); - break; - - case DW_ATE_signed: - if (!type_name.empty()) { - if (type_name == "wchar_t" && - QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) && - (getTargetInfo() && - TargetInfo::isTypeSigned(getTargetInfo()->getWCharType()))) - return GetType(ast.WCharTy); - if (type_name == "void" && - QualTypeMatchesBitSize(bit_size, ast, ast.VoidTy)) - return GetType(ast.VoidTy); - if (type_name.contains("long long") && - QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy)) - return GetType(ast.LongLongTy); - if (type_name.contains("long") && - QualTypeMatchesBitSize(bit_size, ast, ast.LongTy)) - return GetType(ast.LongTy); - if (type_name.contains("short") && - QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy)) - return GetType(ast.ShortTy); - if (type_name.contains("char")) { - if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) - return GetType(ast.CharTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy)) - return GetType(ast.SignedCharTy); - } - if (type_name.contains("int")) { - if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy)) - return GetType(ast.IntTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty)) - return GetType(ast.Int128Ty); - } - } - // We weren't able to match up a type name, just search by size - if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) - return GetType(ast.CharTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy)) - return GetType(ast.ShortTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy)) - return GetType(ast.IntTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy)) - return GetType(ast.LongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy)) - return GetType(ast.LongLongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty)) - return GetType(ast.Int128Ty); - break; - - case DW_ATE_signed_char: - if (ast.getLangOpts().CharIsSigned && type_name == "char") { - if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) - return GetType(ast.CharTy); - } - if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy)) - return GetType(ast.SignedCharTy); - break; - - case DW_ATE_unsigned: - if (!type_name.empty()) { - if (type_name == "wchar_t") { - if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) { - if (!(getTargetInfo() && - TargetInfo::isTypeSigned(getTargetInfo()->getWCharType()))) - return GetType(ast.WCharTy); - } - } - if (type_name.contains("long long")) { - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy)) - return GetType(ast.UnsignedLongLongTy); - } else if (type_name.contains("long")) { - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy)) - return GetType(ast.UnsignedLongTy); - } else if (type_name.contains("short")) { - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) - return GetType(ast.UnsignedShortTy); - } else if (type_name.contains("char")) { - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) - return GetType(ast.UnsignedCharTy); - } else if (type_name.contains("int")) { - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) - return GetType(ast.UnsignedIntTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty)) - return GetType(ast.UnsignedInt128Ty); - } - } - // We weren't able to match up a type name, just search by size - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) - return GetType(ast.UnsignedCharTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) - return GetType(ast.UnsignedShortTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) - return GetType(ast.UnsignedIntTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy)) - return GetType(ast.UnsignedLongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy)) - return GetType(ast.UnsignedLongLongTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty)) - return GetType(ast.UnsignedInt128Ty); - break; - - case DW_ATE_unsigned_char: - if (!ast.getLangOpts().CharIsSigned && type_name == "char") { - if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) - return GetType(ast.CharTy); - } - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) - return GetType(ast.UnsignedCharTy); - if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) - return GetType(ast.UnsignedShortTy); - break; - - case DW_ATE_imaginary_float: - break; - - case DW_ATE_UTF: - if (!type_name.empty()) { - if (type_name == "char16_t") - return GetType(ast.Char16Ty); - if (type_name == "char32_t") - return GetType(ast.Char32Ty); - if (type_name == "char8_t") - return GetType(ast.Char8Ty); - } - break; - } - // This assert should fire for anything that we don't catch above so we know - // to fix any issues we run into. - if (!type_name.empty()) { - std::string type_name_str = type_name.str(); - Host::SystemLog(Host::eSystemLogError, - "error: need to add support for DW_TAG_base_type '%s' " - "encoded with DW_ATE = 0x%x, bit_size = %u\n", - type_name_str.c_str(), dw_ate, bit_size); - } else { - 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 CompilerType(); -} - -CompilerType ClangASTContext::GetCStringType(bool is_const) { - ASTContext &ast = getASTContext(); - QualType char_type(ast.CharTy); - - if (is_const) - char_type.addConst(); - - return GetType(ast.getPointerType(char_type)); -} - -bool ClangASTContext::AreTypesSame(CompilerType type1, CompilerType type2, - bool ignore_qualifiers) { - 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 = ClangUtil::GetQualType(type1); - QualType type2_qual = ClangUtil::GetQualType(type2); - - if (ignore_qualifiers) { - type1_qual = type1_qual.getUnqualifiedType(); - type2_qual = type2_qual.getUnqualifiedType(); - } - - return ast->getASTContext().hasSameType(type1_qual, type2_qual); -} - -CompilerType ClangASTContext::GetTypeForDecl(void *opaque_decl) { - if (!opaque_decl) - return CompilerType(); - - clang::Decl *decl = static_cast<clang::Decl *>(opaque_decl); - if (auto *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl)) - return GetTypeForDecl(named_decl); - return CompilerType(); -} - -CompilerDeclContext ClangASTContext::CreateDeclContext(DeclContext *ctx) { - // Check that the DeclContext actually belongs to this ASTContext. - assert(&ctx->getParentASTContext() == &getASTContext()); - return CompilerDeclContext(this, ctx); -} - -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 CompilerType(); -} - -CompilerType ClangASTContext::GetTypeForDecl(TagDecl *decl) { - return GetType(getASTContext().getTagDeclType(decl)); -} - -CompilerType ClangASTContext::GetTypeForDecl(ObjCInterfaceDecl *decl) { - return GetType(getASTContext().getObjCInterfaceType(decl)); -} - -#pragma mark Structure, Unions, Classes - -CompilerType ClangASTContext::CreateRecordType(DeclContext *decl_ctx, - AccessType access_type, - llvm::StringRef name, int kind, - LanguageType language, - ClangASTMetadata *metadata, - bool exports_symbols) { - ASTContext &ast = getASTContext(); - - if (decl_ctx == nullptr) - decl_ctx = ast.getTranslationUnitDecl(); - - if (language == eLanguageTypeObjC || - language == eLanguageTypeObjC_plus_plus) { - bool isForwardDecl = true; - bool isInternal = false; - return CreateObjCClass(name, decl_ctx, isForwardDecl, isInternal, metadata); - } - - // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and - // we will need to update this code. I was told to currently always use the - // CXXRecordDecl class since we often don't know from debug information if - // something is struct or a class, so we default to always use the more - // complete definition just in case. - - bool has_name = !name.empty(); - - CXXRecordDecl *decl = CXXRecordDecl::Create( - ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), SourceLocation(), - has_name ? &ast.Idents.get(name) : nullptr); - - if (!has_name) { - // In C++ a lambda is also represented as an unnamed class. This is - // different from an *anonymous class* that the user wrote: - // - // struct A { - // // anonymous class (GNU/MSVC extension) - // struct { - // int x; - // }; - // // unnamed class within a class - // struct { - // int y; - // } B; - // }; - // - // void f() { - // // unammed class outside of a class - // struct { - // int z; - // } C; - // } - // - // Anonymous classes is a GNU/MSVC extension that clang supports. It - // requires the anonymous class be embedded within a class. So the new - // heuristic verifies this condition. - if (isa<CXXRecordDecl>(decl_ctx) && exports_symbols) - decl->setAnonymousStructOrUnion(true); - } - - if (decl) { - if (metadata) - SetMetadata(decl, *metadata); - - if (access_type != eAccessNone) - decl->setAccess(ConvertAccessTypeToAccessSpecifier(access_type)); - - if (decl_ctx) - decl_ctx->addDecl(decl); - - return GetType(ast.getTagDeclType(decl)); - } - return CompilerType(); -} - -namespace { - bool IsValueParam(const clang::TemplateArgument &argument) { - return argument.getKind() == TemplateArgument::Integral; - } -} - -static TemplateParameterList *CreateTemplateParameterList( - ASTContext *ast, - const ClangASTContext::TemplateParameterInfos &template_param_infos, - llvm::SmallVector<NamedDecl *, 8> &template_param_decls) { - const bool parameter_pack = false; - const bool is_typename = false; - const unsigned depth = 0; - const size_t num_template_params = template_param_infos.args.size(); - DeclContext *const decl_context = - ast->getTranslationUnitDecl(); // Is this the right decl context?, - for (size_t i = 0; i < num_template_params; ++i) { - const char *name = template_param_infos.names[i]; - - IdentifierInfo *identifier_info = nullptr; - if (name && name[0]) - identifier_info = &ast->Idents.get(name); - if (IsValueParam(template_param_infos.args[i])) { - template_param_decls.push_back(NonTypeTemplateParmDecl::Create( - *ast, decl_context, - SourceLocation(), SourceLocation(), depth, i, identifier_info, - template_param_infos.args[i].getIntegralType(), parameter_pack, - nullptr)); - - } else { - template_param_decls.push_back(TemplateTypeParmDecl::Create( - *ast, decl_context, - SourceLocation(), SourceLocation(), depth, i, identifier_info, - is_typename, parameter_pack)); - } - } - - if (template_param_infos.packed_args) { - IdentifierInfo *identifier_info = nullptr; - if (template_param_infos.pack_name && template_param_infos.pack_name[0]) - identifier_info = &ast->Idents.get(template_param_infos.pack_name); - const bool parameter_pack_true = true; - - if (!template_param_infos.packed_args->args.empty() && - IsValueParam(template_param_infos.packed_args->args[0])) { - template_param_decls.push_back(NonTypeTemplateParmDecl::Create( - *ast, decl_context, SourceLocation(), SourceLocation(), depth, - num_template_params, identifier_info, - template_param_infos.packed_args->args[0].getIntegralType(), - parameter_pack_true, nullptr)); - } else { - template_param_decls.push_back(TemplateTypeParmDecl::Create( - *ast, decl_context, SourceLocation(), SourceLocation(), depth, - num_template_params, identifier_info, is_typename, - parameter_pack_true)); - } - } - clang::Expr *const requires_clause = nullptr; // TODO: Concepts - TemplateParameterList *template_param_list = TemplateParameterList::Create( - *ast, SourceLocation(), SourceLocation(), template_param_decls, - SourceLocation(), requires_clause); - return template_param_list; -} - -clang::FunctionTemplateDecl *ClangASTContext::CreateFunctionTemplateDecl( - clang::DeclContext *decl_ctx, clang::FunctionDecl *func_decl, - const char *name, const TemplateParameterInfos &template_param_infos) { - // /// Create a function template node. - ASTContext &ast = getASTContext(); - - llvm::SmallVector<NamedDecl *, 8> template_param_decls; - - TemplateParameterList *template_param_list = CreateTemplateParameterList( - &ast, template_param_infos, template_param_decls); - FunctionTemplateDecl *func_tmpl_decl = FunctionTemplateDecl::Create( - ast, decl_ctx, func_decl->getLocation(), func_decl->getDeclName(), - template_param_list, func_decl); - - for (size_t i = 0, template_param_decl_count = template_param_decls.size(); - i < template_param_decl_count; ++i) { - // TODO: verify which decl context we should put template_param_decls into.. - template_param_decls[i]->setDeclContext(func_decl); - } - // Function templates inside a record need to have an access specifier. - // It doesn't matter what access specifier we give the template as LLDB - // anyway allows accessing everything inside a record. - if (decl_ctx->isRecord()) - func_tmpl_decl->setAccess(clang::AccessSpecifier::AS_public); - - return func_tmpl_decl; -} - -void ClangASTContext::CreateFunctionTemplateSpecializationInfo( - FunctionDecl *func_decl, clang::FunctionTemplateDecl *func_tmpl_decl, - const TemplateParameterInfos &infos) { - TemplateArgumentList *template_args_ptr = - TemplateArgumentList::CreateCopy(func_decl->getASTContext(), infos.args); - - func_decl->setFunctionTemplateSpecialization(func_tmpl_decl, - template_args_ptr, nullptr); -} - -ClassTemplateDecl *ClangASTContext::CreateClassTemplateDecl( - DeclContext *decl_ctx, lldb::AccessType access_type, const char *class_name, - int kind, const TemplateParameterInfos &template_param_infos) { - ASTContext &ast = getASTContext(); - - ClassTemplateDecl *class_template_decl = nullptr; - if (decl_ctx == nullptr) - decl_ctx = ast.getTranslationUnitDecl(); - - IdentifierInfo &identifier_info = ast.Idents.get(class_name); - DeclarationName decl_name(&identifier_info); - - clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name); - - for (NamedDecl *decl : result) { - class_template_decl = dyn_cast<clang::ClassTemplateDecl>(decl); - if (class_template_decl) - return class_template_decl; - } - - llvm::SmallVector<NamedDecl *, 8> template_param_decls; - - TemplateParameterList *template_param_list = CreateTemplateParameterList( - &ast, template_param_infos, template_param_decls); - - CXXRecordDecl *template_cxx_decl = CXXRecordDecl::Create( - ast, (TagDecl::TagKind)kind, - decl_ctx, // What decl context do we use here? TU? The actual decl - // context? - SourceLocation(), SourceLocation(), &identifier_info); - - for (size_t i = 0, template_param_decl_count = template_param_decls.size(); - i < template_param_decl_count; ++i) { - template_param_decls[i]->setDeclContext(template_cxx_decl); - } - - // With templated classes, we say that a class is templated with - // specializations, but that the bare class has no functions. - // template_cxx_decl->startDefinition(); - // template_cxx_decl->completeDefinition(); - - class_template_decl = ClassTemplateDecl::Create( - ast, - decl_ctx, // What decl context do we use here? TU? The actual decl - // context? - SourceLocation(), decl_name, template_param_list, template_cxx_decl); - template_cxx_decl->setDescribedClassTemplate(class_template_decl); - - if (class_template_decl) { - if (access_type != eAccessNone) - class_template_decl->setAccess( - ConvertAccessTypeToAccessSpecifier(access_type)); - - // if (TagDecl *ctx_tag_decl = dyn_cast<TagDecl>(decl_ctx)) - // CompleteTagDeclarationDefinition(GetTypeForDecl(ctx_tag_decl)); - - decl_ctx->addDecl(class_template_decl); - -#ifdef LLDB_CONFIGURATION_DEBUG - VerifyDecl(class_template_decl); -#endif - } - - return class_template_decl; -} - -TemplateTemplateParmDecl * -ClangASTContext::CreateTemplateTemplateParmDecl(const char *template_name) { - ASTContext &ast = getASTContext(); - - auto *decl_ctx = ast.getTranslationUnitDecl(); - - IdentifierInfo &identifier_info = ast.Idents.get(template_name); - llvm::SmallVector<NamedDecl *, 8> template_param_decls; - - ClangASTContext::TemplateParameterInfos template_param_infos; - TemplateParameterList *template_param_list = CreateTemplateParameterList( - &ast, template_param_infos, template_param_decls); - - // LLDB needs to create those decls only to be able to display a - // type that includes a template template argument. Only the name matters for - // this purpose, so we use dummy values for the other characterisitcs of the - // type. - return TemplateTemplateParmDecl::Create( - ast, decl_ctx, SourceLocation(), - /*Depth*/ 0, /*Position*/ 0, - /*IsParameterPack*/ false, &identifier_info, template_param_list); -} - -ClassTemplateSpecializationDecl * -ClangASTContext::CreateClassTemplateSpecializationDecl( - DeclContext *decl_ctx, ClassTemplateDecl *class_template_decl, int kind, - const TemplateParameterInfos &template_param_infos) { - ASTContext &ast = getASTContext(); - llvm::SmallVector<clang::TemplateArgument, 2> args( - template_param_infos.args.size() + - (template_param_infos.packed_args ? 1 : 0)); - std::copy(template_param_infos.args.begin(), template_param_infos.args.end(), - args.begin()); - if (template_param_infos.packed_args) { - args[args.size() - 1] = TemplateArgument::CreatePackCopy( - ast, template_param_infos.packed_args->args); - } - ClassTemplateSpecializationDecl *class_template_specialization_decl = - ClassTemplateSpecializationDecl::Create( - ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), - SourceLocation(), class_template_decl, args, nullptr); - - class_template_specialization_decl->setSpecializationKind( - TSK_ExplicitSpecialization); - - return class_template_specialization_decl; -} - -CompilerType ClangASTContext::CreateClassTemplateSpecializationType( - ClassTemplateSpecializationDecl *class_template_specialization_decl) { - if (class_template_specialization_decl) { - ASTContext &ast = getASTContext(); - return GetType(ast.getTagDeclType(class_template_specialization_decl)); - } - return CompilerType(); -} - -static inline bool check_op_param(bool is_method, - clang::OverloadedOperatorKind op_kind, - bool unary, bool binary, - uint32_t num_params) { - // Special-case call since it can take any number of operands - if (op_kind == OO_Call) - return true; - - // The parameter count doesn't include "this" - if (is_method) - ++num_params; - if (num_params == 1) - return unary; - if (num_params == 2) - return binary; - else - return false; -} - -bool ClangASTContext::CheckOverloadedOperatorKindParameterCount( - bool is_method, clang::OverloadedOperatorKind op_kind, - uint32_t num_params) { - switch (op_kind) { - default: - break; - // C++ standard allows any number of arguments to new/delete - case OO_New: - case OO_Array_New: - case OO_Delete: - case OO_Array_Delete: - return true; - } - -#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ - case OO_##Name: \ - return check_op_param(is_method, op_kind, Unary, Binary, num_params); - switch (op_kind) { -#include "clang/Basic/OperatorKinds.def" - default: - break; - } - return false; -} - -clang::AccessSpecifier -ClangASTContext::UnifyAccessSpecifiers(clang::AccessSpecifier lhs, - clang::AccessSpecifier rhs) { - // Make the access equal to the stricter of the field and the nested field's - // access - if (lhs == AS_none || rhs == AS_none) - return AS_none; - if (lhs == AS_private || rhs == AS_private) - return AS_private; - if (lhs == AS_protected || rhs == AS_protected) - return AS_protected; - return AS_public; -} - -bool ClangASTContext::FieldIsBitfield(FieldDecl *field, - uint32_t &bitfield_bit_size) { - ASTContext &ast = getASTContext(); - if (field == nullptr) - return false; - - if (field->isBitField()) { - Expr *bit_width_expr = field->getBitWidth(); - if (bit_width_expr) { - llvm::APSInt bit_width_apsint; - if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, ast)) { - bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); - return true; - } - } - } - return false; -} - -bool ClangASTContext::RecordHasFields(const RecordDecl *record_decl) { - if (record_decl == nullptr) - return false; - - if (!record_decl->field_empty()) - return true; - - // No fields, lets check this is a CXX record and check the base classes - const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); - if (cxx_record_decl) { - CXXRecordDecl::base_class_const_iterator base_class, base_class_end; - for (base_class = cxx_record_decl->bases_begin(), - base_class_end = cxx_record_decl->bases_end(); - base_class != base_class_end; ++base_class) { - const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>( - base_class->getType()->getAs<RecordType>()->getDecl()); - if (RecordHasFields(base_class_decl)) - return true; - } - } - return false; -} - -#pragma mark Objective-C Classes - -CompilerType ClangASTContext::CreateObjCClass(llvm::StringRef name, - DeclContext *decl_ctx, - bool isForwardDecl, - bool isInternal, - ClangASTMetadata *metadata) { - ASTContext &ast = getASTContext(); - assert(!name.empty()); - if (decl_ctx == nullptr) - decl_ctx = ast.getTranslationUnitDecl(); - - ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create( - ast, decl_ctx, SourceLocation(), &ast.Idents.get(name), nullptr, nullptr, - SourceLocation(), - /*isForwardDecl,*/ - isInternal); - - if (decl && metadata) - SetMetadata(decl, *metadata); - - return GetType(ast.getObjCInterfaceType(decl)); -} - -static inline bool BaseSpecifierIsEmpty(const CXXBaseSpecifier *b) { - return !ClangASTContext::RecordHasFields(b->getType()->getAsCXXRecordDecl()); -} - -uint32_t -ClangASTContext::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl, - bool omit_empty_base_classes) { - uint32_t num_bases = 0; - if (cxx_record_decl) { - if (omit_empty_base_classes) { - CXXRecordDecl::base_class_const_iterator base_class, base_class_end; - for (base_class = cxx_record_decl->bases_begin(), - base_class_end = cxx_record_decl->bases_end(); - base_class != base_class_end; ++base_class) { - // Skip empty base classes - if (omit_empty_base_classes) { - if (BaseSpecifierIsEmpty(base_class)) - continue; - } - ++num_bases; - } - } else - num_bases = cxx_record_decl->getNumBases(); - } - return num_bases; -} - -#pragma mark Namespace Declarations - -NamespaceDecl *ClangASTContext::GetUniqueNamespaceDeclaration( - const char *name, DeclContext *decl_ctx, bool is_inline) { - NamespaceDecl *namespace_decl = nullptr; - ASTContext &ast = getASTContext(); - TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl(); - if (decl_ctx == nullptr) - decl_ctx = translation_unit_decl; - - if (name) { - IdentifierInfo &identifier_info = ast.Idents.get(name); - DeclarationName decl_name(&identifier_info); - clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name); - for (NamedDecl *decl : result) { - namespace_decl = dyn_cast<clang::NamespaceDecl>(decl); - if (namespace_decl) - return namespace_decl; - } - - namespace_decl = - NamespaceDecl::Create(ast, decl_ctx, is_inline, SourceLocation(), - SourceLocation(), &identifier_info, nullptr); - - decl_ctx->addDecl(namespace_decl); - } else { - if (decl_ctx == translation_unit_decl) { - namespace_decl = translation_unit_decl->getAnonymousNamespace(); - if (namespace_decl) - return namespace_decl; - - namespace_decl = - NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(), - SourceLocation(), nullptr, nullptr); - translation_unit_decl->setAnonymousNamespace(namespace_decl); - translation_unit_decl->addDecl(namespace_decl); - assert(namespace_decl == translation_unit_decl->getAnonymousNamespace()); - } else { - NamespaceDecl *parent_namespace_decl = cast<NamespaceDecl>(decl_ctx); - if (parent_namespace_decl) { - namespace_decl = parent_namespace_decl->getAnonymousNamespace(); - if (namespace_decl) - return namespace_decl; - namespace_decl = - NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(), - SourceLocation(), nullptr, nullptr); - parent_namespace_decl->setAnonymousNamespace(namespace_decl); - parent_namespace_decl->addDecl(namespace_decl); - assert(namespace_decl == - parent_namespace_decl->getAnonymousNamespace()); - } else { - assert(false && "GetUniqueNamespaceDeclaration called with no name and " - "no namespace as decl_ctx"); - } - } - } -#ifdef LLDB_CONFIGURATION_DEBUG - VerifyDecl(namespace_decl); -#endif - return namespace_decl; -} - -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) { - auto *translation_unit = getASTContext().getTranslationUnitDecl(); - 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; -} - -lldb::opaque_compiler_type_t -ClangASTContext::GetOpaqueCompilerType(clang::ASTContext *ast, - lldb::BasicType basic_type) { - switch (basic_type) { - case eBasicTypeVoid: - return ast->VoidTy.getAsOpaquePtr(); - case eBasicTypeChar: - return ast->CharTy.getAsOpaquePtr(); - case eBasicTypeSignedChar: - return ast->SignedCharTy.getAsOpaquePtr(); - case eBasicTypeUnsignedChar: - return ast->UnsignedCharTy.getAsOpaquePtr(); - case eBasicTypeWChar: - return ast->getWCharType().getAsOpaquePtr(); - case eBasicTypeSignedWChar: - return ast->getSignedWCharType().getAsOpaquePtr(); - case eBasicTypeUnsignedWChar: - return ast->getUnsignedWCharType().getAsOpaquePtr(); - case eBasicTypeChar16: - return ast->Char16Ty.getAsOpaquePtr(); - case eBasicTypeChar32: - return ast->Char32Ty.getAsOpaquePtr(); - case eBasicTypeShort: - return ast->ShortTy.getAsOpaquePtr(); - case eBasicTypeUnsignedShort: - return ast->UnsignedShortTy.getAsOpaquePtr(); - case eBasicTypeInt: - return ast->IntTy.getAsOpaquePtr(); - case eBasicTypeUnsignedInt: - return ast->UnsignedIntTy.getAsOpaquePtr(); - case eBasicTypeLong: - return ast->LongTy.getAsOpaquePtr(); - case eBasicTypeUnsignedLong: - return ast->UnsignedLongTy.getAsOpaquePtr(); - case eBasicTypeLongLong: - return ast->LongLongTy.getAsOpaquePtr(); - case eBasicTypeUnsignedLongLong: - return ast->UnsignedLongLongTy.getAsOpaquePtr(); - case eBasicTypeInt128: - return ast->Int128Ty.getAsOpaquePtr(); - case eBasicTypeUnsignedInt128: - return ast->UnsignedInt128Ty.getAsOpaquePtr(); - case eBasicTypeBool: - return ast->BoolTy.getAsOpaquePtr(); - case eBasicTypeHalf: - return ast->HalfTy.getAsOpaquePtr(); - case eBasicTypeFloat: - return ast->FloatTy.getAsOpaquePtr(); - case eBasicTypeDouble: - return ast->DoubleTy.getAsOpaquePtr(); - case eBasicTypeLongDouble: - return ast->LongDoubleTy.getAsOpaquePtr(); - case eBasicTypeFloatComplex: - return ast->FloatComplexTy.getAsOpaquePtr(); - case eBasicTypeDoubleComplex: - return ast->DoubleComplexTy.getAsOpaquePtr(); - case eBasicTypeLongDoubleComplex: - return ast->LongDoubleComplexTy.getAsOpaquePtr(); - case eBasicTypeObjCID: - return ast->getObjCIdType().getAsOpaquePtr(); - case eBasicTypeObjCClass: - return ast->getObjCClassType().getAsOpaquePtr(); - case eBasicTypeObjCSel: - return ast->getObjCSelType().getAsOpaquePtr(); - case eBasicTypeNullPtr: - return ast->NullPtrTy.getAsOpaquePtr(); - default: - return nullptr; - } -} - -#pragma mark Function Types - -clang::DeclarationName -ClangASTContext::GetDeclarationName(const char *name, - const CompilerType &function_clang_type) { - if (!name || !name[0]) - return clang::DeclarationName(); - - clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; - if (!IsOperator(name, op_kind) || op_kind == clang::NUM_OVERLOADED_OPERATORS) - return DeclarationName(&getASTContext().Idents.get( - name)); // Not operator, but a regular function. - - // 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. - clang::QualType method_qual_type(ClangUtil::GetQualType(function_clang_type)); - const clang::FunctionProtoType *function_type = - llvm::dyn_cast<clang::FunctionProtoType>(method_qual_type.getTypePtr()); - if (function_type == nullptr) - return clang::DeclarationName(); - - const bool is_method = false; - const unsigned int num_params = function_type->getNumParams(); - if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount( - is_method, op_kind, num_params)) - return clang::DeclarationName(); - - return getASTContext().DeclarationNames.getCXXOperatorName(op_kind); -} - -FunctionDecl *ClangASTContext::CreateFunctionDeclaration( - DeclContext *decl_ctx, const char *name, - const CompilerType &function_clang_type, int storage, bool is_inline) { - FunctionDecl *func_decl = nullptr; - ASTContext &ast = getASTContext(); - if (decl_ctx == nullptr) - decl_ctx = ast.getTranslationUnitDecl(); - - const bool hasWrittenPrototype = true; - const bool isConstexprSpecified = false; - - clang::DeclarationName declarationName = - GetDeclarationName(name, function_clang_type); - func_decl = FunctionDecl::Create( - ast, decl_ctx, SourceLocation(), SourceLocation(), declarationName, - ClangUtil::GetQualType(function_clang_type), nullptr, - (clang::StorageClass)storage, is_inline, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); - if (func_decl) - decl_ctx->addDecl(func_decl); - -#ifdef LLDB_CONFIGURATION_DEBUG - VerifyDecl(func_decl); -#endif - - return func_decl; -} - -CompilerType -ClangASTContext::CreateFunctionType(const CompilerType &result_type, - const CompilerType *args, unsigned num_args, - bool is_variadic, unsigned type_quals, - clang::CallingConv cc) { - if (!result_type || !ClangUtil::IsClangType(result_type)) - return CompilerType(); // invalid return type - - std::vector<QualType> qual_type_args; - if (num_args > 0 && args == nullptr) - return CompilerType(); // invalid argument array passed in - - // Verify that all arguments are valid and the right type - for (unsigned i = 0; i < num_args; ++i) { - if (args[i]) { - // Make sure we have a clang type in args[i] and not a type from another - // language whose name might match - const bool is_clang_type = ClangUtil::IsClangType(args[i]); - lldbassert(is_clang_type); - if (is_clang_type) - qual_type_args.push_back(ClangUtil::GetQualType(args[i])); - else - return CompilerType(); // invalid argument type (must be a clang type) - } else - return CompilerType(); // invalid argument type (empty) - } - - // TODO: Detect calling convention in DWARF? - FunctionProtoType::ExtProtoInfo proto_info; - proto_info.ExtInfo = cc; - proto_info.Variadic = is_variadic; - proto_info.ExceptionSpec = EST_None; - proto_info.TypeQuals = clang::Qualifiers::fromFastMask(type_quals); - proto_info.RefQualifier = RQ_None; - - return GetType(getASTContext().getFunctionType( - ClangUtil::GetQualType(result_type), qual_type_args, proto_info)); -} - -ParmVarDecl *ClangASTContext::CreateParameterDeclaration( - clang::DeclContext *decl_ctx, const char *name, - const CompilerType ¶m_type, int storage, bool add_decl) { - ASTContext &ast = getASTContext(); - auto *decl = - ParmVarDecl::Create(ast, decl_ctx, SourceLocation(), SourceLocation(), - name && name[0] ? &ast.Idents.get(name) : nullptr, - ClangUtil::GetQualType(param_type), nullptr, - (clang::StorageClass)storage, nullptr); - if (add_decl) - decl_ctx->addDecl(decl); - - return decl; -} - -void ClangASTContext::SetFunctionParameters(FunctionDecl *function_decl, - ParmVarDecl **params, - unsigned num_params) { - if (function_decl) - function_decl->setParams(ArrayRef<ParmVarDecl *>(params, num_params)); -} - -CompilerType -ClangASTContext::CreateBlockPointerType(const CompilerType &function_type) { - QualType block_type = m_ast_up->getBlockPointerType( - clang::QualType::getFromOpaquePtr(function_type.GetOpaqueQualType())); - - return GetType(block_type); -} - -#pragma mark Array Types - -CompilerType ClangASTContext::CreateArrayType(const CompilerType &element_type, - size_t element_count, - bool is_vector) { - if (element_type.IsValid()) { - ASTContext &ast = getASTContext(); - - if (is_vector) { - return GetType(ast.getExtVectorType(ClangUtil::GetQualType(element_type), - element_count)); - } else { - - llvm::APInt ap_element_count(64, element_count); - if (element_count == 0) { - return GetType(ast.getIncompleteArrayType( - ClangUtil::GetQualType(element_type), clang::ArrayType::Normal, 0)); - } else { - return GetType(ast.getConstantArrayType( - ClangUtil::GetQualType(element_type), ap_element_count, nullptr, - clang::ArrayType::Normal, 0)); - } - } - } - return CompilerType(); -} - -CompilerType ClangASTContext::CreateStructForIdentifier( - ConstString type_name, - const std::initializer_list<std::pair<const char *, CompilerType>> - &type_fields, - bool packed) { - CompilerType type; - if (!type_name.IsEmpty() && - (type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)) - .IsValid()) { - lldbassert(0 && "Trying to create a type for an existing name"); - return type; - } - - type = CreateRecordType(nullptr, lldb::eAccessPublic, type_name.GetCString(), - clang::TTK_Struct, lldb::eLanguageTypeC); - StartTagDeclarationDefinition(type); - for (const auto &field : type_fields) - AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic, - 0); - if (packed) - SetIsPacked(type); - CompleteTagDeclarationDefinition(type); - return type; -} - -CompilerType ClangASTContext::GetOrCreateStructForIdentifier( - ConstString type_name, - const std::initializer_list<std::pair<const char *, CompilerType>> - &type_fields, - bool packed) { - CompilerType type; - if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)).IsValid()) - return type; - - return CreateStructForIdentifier(type_name, type_fields, packed); -} - -#pragma mark Enumeration Types - -CompilerType -ClangASTContext::CreateEnumerationType(const char *name, DeclContext *decl_ctx, - const Declaration &decl, - const CompilerType &integer_clang_type, - bool is_scoped) { - // 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 IsFixed = false; - - EnumDecl *enum_decl = EnumDecl::Create( - ast, decl_ctx, SourceLocation(), SourceLocation(), - name && name[0] ? &ast.Idents.get(name) : nullptr, nullptr, - is_scoped, // IsScoped - is_scoped, // IsScopedUsingClassTag - false); // IsFixed - - if (enum_decl) { - if (decl_ctx) - decl_ctx->addDecl(enum_decl); - - // TODO: check if we should be setting the promotion type too? - enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type)); - - enum_decl->setAccess(AS_public); // TODO respect what's in the debug info - - return GetType(ast.getTagDeclType(enum_decl)); - } - return CompilerType(); -} - -CompilerType ClangASTContext::GetIntTypeFromBitSize(size_t bit_size, - bool is_signed) { - clang::ASTContext &ast = getASTContext(); - - if (is_signed) { - if (bit_size == ast.getTypeSize(ast.SignedCharTy)) - return GetType(ast.SignedCharTy); - - if (bit_size == ast.getTypeSize(ast.ShortTy)) - return GetType(ast.ShortTy); - - if (bit_size == ast.getTypeSize(ast.IntTy)) - return GetType(ast.IntTy); - - if (bit_size == ast.getTypeSize(ast.LongTy)) - return GetType(ast.LongTy); - - if (bit_size == ast.getTypeSize(ast.LongLongTy)) - return GetType(ast.LongLongTy); - - if (bit_size == ast.getTypeSize(ast.Int128Ty)) - return GetType(ast.Int128Ty); - } else { - if (bit_size == ast.getTypeSize(ast.UnsignedCharTy)) - return GetType(ast.UnsignedCharTy); - - if (bit_size == ast.getTypeSize(ast.UnsignedShortTy)) - return GetType(ast.UnsignedShortTy); - - if (bit_size == ast.getTypeSize(ast.UnsignedIntTy)) - return GetType(ast.UnsignedIntTy); - - if (bit_size == ast.getTypeSize(ast.UnsignedLongTy)) - return GetType(ast.UnsignedLongTy); - - if (bit_size == ast.getTypeSize(ast.UnsignedLongLongTy)) - return GetType(ast.UnsignedLongLongTy); - - if (bit_size == ast.getTypeSize(ast.UnsignedInt128Ty)) - return GetType(ast.UnsignedInt128Ty); - } - return CompilerType(); -} - -CompilerType ClangASTContext::GetPointerSizedIntType(bool is_signed) { - return GetIntTypeFromBitSize( - getASTContext().getTypeSize(getASTContext().VoidPtrTy), is_signed); -} - -void ClangASTContext::DumpDeclContextHiearchy(clang::DeclContext *decl_ctx) { - 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) { - 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()); - } - } -} - -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 (true) { - 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 (true) { - 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) { - if (!decl) - return false; - - ExternalASTSource *ast_source = ast->getExternalSource(); - - if (!ast_source) - return false; - - if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl)) { - if (tag_decl->isCompleteDefinition()) - return true; - - if (!tag_decl->hasExternalLexicalStorage()) - return false; - - ast_source->CompleteType(tag_decl); - - return !tag_decl->getTypeForDecl()->isIncompleteType(); - } else if (clang::ObjCInterfaceDecl *objc_interface_decl = - llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) { - if (objc_interface_decl->getDefinition()) - return true; - - if (!objc_interface_decl->hasExternalLexicalStorage()) - return false; - - ast_source->CompleteType(objc_interface_decl); - - return !objc_interface_decl->getTypeForDecl()->isIncompleteType(); - } else { - return false; - } -} - -void ClangASTContext::SetMetadataAsUserID(const clang::Decl *decl, - user_id_t user_id) { - ClangASTMetadata meta_data; - meta_data.SetUserID(user_id); - SetMetadata(decl, meta_data); -} - -void ClangASTContext::SetMetadataAsUserID(const clang::Type *type, - user_id_t user_id) { - ClangASTMetadata meta_data; - meta_data.SetUserID(user_id); - SetMetadata(type, meta_data); -} - -void ClangASTContext::SetMetadata(const clang::Decl *object, - ClangASTMetadata &metadata) { - m_decl_metadata[object] = metadata; -} - -void ClangASTContext::SetMetadata(const clang::Type *object, - ClangASTMetadata &metadata) { - m_type_metadata[object] = metadata; -} - -ClangASTMetadata *ClangASTContext::GetMetadata(const clang::Decl *object) { - auto It = m_decl_metadata.find(object); - if (It != m_decl_metadata.end()) - return &It->second; - return nullptr; -} - -ClangASTMetadata *ClangASTContext::GetMetadata(const clang::Type *object) { - auto It = m_type_metadata.find(object); - if (It != m_type_metadata.end()) - return &It->second; - return nullptr; -} - -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::SetDefaultAccessForRecordFields( - clang::RecordDecl *record_decl, int default_accessibility, - int *assigned_accessibilities, size_t num_assigned_accessibilities) { - 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; -} - -clang::DeclContext * -ClangASTContext::GetDeclContextForType(const CompilerType &type) { - return GetDeclContextForType(ClangUtil::GetQualType(type)); -} - -/// Aggressively desugar the provided type, skipping past various kinds of -/// syntactic sugar and other constructs one typically wants to ignore. -/// The \p mask argument allows one to skip certain kinds of simplifications, -/// when one wishes to handle a certain kind of type directly. -static QualType -RemoveWrappingTypes(QualType type, ArrayRef<clang::Type::TypeClass> mask = {}) { - while (true) { - if (find(mask, type->getTypeClass()) != mask.end()) - return type; - switch (type->getTypeClass()) { - // This is not fully correct as _Atomic is more than sugar, but it is - // sufficient for the purposes we care about. - case clang::Type::Atomic: - type = cast<clang::AtomicType>(type)->getValueType(); - break; - case clang::Type::Auto: - case clang::Type::Decltype: - case clang::Type::Elaborated: - case clang::Type::Paren: - case clang::Type::Typedef: - case clang::Type::TypeOf: - case clang::Type::TypeOfExpr: - type = type->getLocallyUnqualifiedSingleStepDesugaredType(); - break; - default: - return type; - } - } -} - -clang::DeclContext * -ClangASTContext::GetDeclContextForType(clang::QualType type) { - if (type.isNull()) - return nullptr; - - clang::QualType qual_type = RemoveWrappingTypes(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(); - default: - break; - } - // No DeclContext in this type... - return nullptr; -} - -static bool GetCompleteQualType(clang::ASTContext *ast, - clang::QualType qual_type, - bool allow_completion = true) { - qual_type = RemoveWrappingTypes(qual_type); - 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->field_begin(); - cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true); - } - } - } - } - 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::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(RemoveWrappingTypes(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; - default: - break; - } - // The clang type does have a value - return false; -} - -bool ClangASTContext::IsAnonymousType(lldb::opaque_compiler_type_t type) { - clang::QualType qual_type(RemoveWrappingTypes(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; - } - 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(RemoveWrappingTypes(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( - this, llvm::cast<clang::ConstantArrayType>(qual_type) - ->getElementType() - .getAsOpaquePtr()); - 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( - this, llvm::cast<clang::IncompleteArrayType>(qual_type) - ->getElementType() - .getAsOpaquePtr()); - if (size) - *size = 0; - if (is_incomplete) - *is_incomplete = true; - return true; - - case clang::Type::VariableArray: - if (element_type_ptr) - element_type_ptr->SetCompilerType( - this, llvm::cast<clang::VariableArrayType>(qual_type) - ->getElementType() - .getAsOpaquePtr()); - if (size) - *size = 0; - if (is_incomplete) - *is_incomplete = false; - return true; - - case clang::Type::DependentSizedArray: - if (element_type_ptr) - element_type_ptr->SetCompilerType( - this, llvm::cast<clang::DependentSizedArrayType>(qual_type) - ->getElementType() - .getAsOpaquePtr()); - if (size) - *size = 0; - if (is_incomplete) - *is_incomplete = false; - return true; - } - 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 = GetType(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(this, ext_vector_type->getElementType().getAsOpaquePtr()); - } - return true; - } - default: - break; - } - return false; -} - -bool ClangASTContext::IsRuntimeGeneratedType( - lldb::opaque_compiler_type_t type) { - clang::DeclContext *decl_ctx = 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 = GetMetadata(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 = RemoveWrappingTypes(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::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(RemoveWrappingTypes(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; - uint64_t base_bitwidth = 0; - for (field_pos = record_decl->field_begin(); field_pos != field_end; - ++field_pos) { - clang::QualType field_qual_type = field_pos->getType(); - uint64_t field_bitwidth = getASTContext().getTypeSize(qual_type); - 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()) { - if (num_fields == 0) { - base_qual_type = field_qual_type; - base_bitwidth = field_bitwidth; - } else { - if (is_hfa) - return 0; - is_hva = true; - if (base_bitwidth != field_bitwidth) - return 0; - if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr()) - return 0; - } - } else - return 0; - ++num_fields; - } - if (base_type_ptr) - *base_type_ptr = CompilerType(this, base_qual_type.getAsOpaquePtr()); - return num_fields; - } - } - } - break; - - 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(GetQualType(type)); - const clang::FunctionProtoType *func = - llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); - if (func) { - if (index < func->getNumParams()) - return CompilerType(this, func->getParamType(index).getAsOpaquePtr()); - } - } - return CompilerType(); -} - -bool ClangASTContext::IsFunctionPointerType(lldb::opaque_compiler_type_t type) { - if (type) { - clang::QualType qual_type = RemoveWrappingTypes(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::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::IsBlockPointerType( - lldb::opaque_compiler_type_t type, - CompilerType *function_pointer_type_ptr) { - if (type) { - clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); - - if (qual_type->isBlockPointerType()) { - if (function_pointer_type_ptr) { - const clang::BlockPointerType *block_pointer_type = - qual_type->getAs<clang::BlockPointerType>(); - QualType pointee_type = block_pointer_type->getPointeeType(); - QualType function_pointer_type = m_ast_up->getPointerType(pointee_type); - *function_pointer_type_ptr = - CompilerType(this, function_pointer_type.getAsOpaquePtr()); - } - return true; - } - - const clang::Type::TypeClass type_class = qual_type->getTypeClass(); - switch (type_class) { - default: - break; - - case clang::Type::LValueReference: - case clang::Type::RValueReference: { - const clang::ReferenceType *reference_type = - llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); - if (reference_type) - return IsBlockPointerType( - reference_type->getPointeeType().getAsOpaquePtr(), - function_pointer_type_ptr); - } 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::IsEnumerationType(lldb::opaque_compiler_type_t type, - bool &is_signed) { - if (type) { - const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>( - GetCanonicalQualType(type)->getCanonicalTypeInternal()); - - if (enum_type) { - IsIntegerType(enum_type->getDecl()->getIntegerType().getAsOpaquePtr(), - is_signed); - return true; - } - } - - return false; -} - -bool ClangASTContext::IsPointerType(lldb::opaque_compiler_type_t type, - CompilerType *pointee_type) { - if (type) { - clang::QualType qual_type = RemoveWrappingTypes(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( - this, llvm::cast<clang::ObjCObjectPointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - return true; - case clang::Type::BlockPointer: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::BlockPointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - return true; - case clang::Type::Pointer: - if (pointee_type) - pointee_type->SetCompilerType(this, - llvm::cast<clang::PointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - return true; - case clang::Type::MemberPointer: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::MemberPointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - return true; - 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 = RemoveWrappingTypes(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( - this, llvm::cast<clang::ObjCObjectPointerType>(qual_type) - ->getPointeeType().getAsOpaquePtr()); - return true; - case clang::Type::BlockPointer: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::BlockPointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - return true; - case clang::Type::Pointer: - if (pointee_type) - pointee_type->SetCompilerType(this, - llvm::cast<clang::PointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - return true; - case clang::Type::MemberPointer: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::MemberPointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - return true; - case clang::Type::LValueReference: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::LValueReferenceType>(qual_type) - ->desugar() - .getAsOpaquePtr()); - return true; - case clang::Type::RValueReference: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::RValueReferenceType>(qual_type) - ->desugar() - .getAsOpaquePtr()); - return true; - 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 = RemoveWrappingTypes(GetCanonicalQualType(type)); - const clang::Type::TypeClass type_class = qual_type->getTypeClass(); - - switch (type_class) { - case clang::Type::LValueReference: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::LValueReferenceType>(qual_type) - ->desugar() - .getAsOpaquePtr()); - if (is_rvalue) - *is_rvalue = false; - return true; - case clang::Type::RValueReference: - if (pointee_type) - pointee_type->SetCompilerType( - this, llvm::cast<clang::RValueReferenceType>(qual_type) - ->desugar() - .getAsOpaquePtr()); - if (is_rvalue) - *is_rvalue = true; - return true; - - 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 (ClangUtil::IsClangType(type)) { - clang::QualType qual_type(ClangUtil::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 (ClangUtil::IsClangType(type)) - return ClangUtil::GetCanonicalQualType(type)->isObjCObjectOrInterfaceType(); - return false; -} - -bool ClangASTContext::IsClassType(lldb::opaque_compiler_type_t type) { - if (!type) - return false; - clang::QualType qual_type(GetCanonicalQualType(type)); - const clang::Type::TypeClass type_class = qual_type->getTypeClass(); - return (type_class == clang::Type::Record); -} - -bool ClangASTContext::IsEnumType(lldb::opaque_compiler_type_t type) { - if (!type) - return false; - clang::QualType qual_type(GetCanonicalQualType(type)); - const clang::Type::TypeClass type_class = qual_type->getTypeClass(); - return (type_class == clang::Type::Enum); -} - -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 = RemoveWrappingTypes(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 (auto objc_pointee_type = - qual_type->getPointeeType().getTypePtrOrNull()) { - if (auto objc_object_type = - llvm::dyn_cast_or_null<clang::ObjCObjectType>( - objc_pointee_type)) { - if (objc_object_type->isObjCClass()) - return false; - } - } - if (dynamic_pointee_type) - dynamic_pointee_type->SetCompilerType( - this, llvm::cast<clang::ObjCObjectPointerType>(qual_type) - ->getPointeeType() - .getAsOpaquePtr()); - 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; - - 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( - this, pointee_qual_type.getAsOpaquePtr()); - 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 = GetMetadata(cxx_record_decl); - if (metadata) - success = metadata->GetIsDynamicCXXType(); - else { - is_complete = GetType(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( - this, pointee_qual_type.getAsOpaquePtr()); - return true; - } - } - } - break; - - case clang::Type::ObjCObject: - case clang::Type::ObjCInterface: - if (check_objc) { - if (dynamic_pointee_type) - dynamic_pointee_type->SetCompilerType( - this, pointee_qual_type.getAsOpaquePtr()); - 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::CanPassInRegisters(const CompilerType &type) { - if (auto *record_decl = - ClangASTContext::GetAsRecordDecl(type)) { - return record_decl->canPassInRegisters(); - } - return false; -} - -bool ClangASTContext::SupportsLanguage(lldb::LanguageType language) { - return ClangASTContextSupportsLanguage(language); -} - -Optional<std::string> -ClangASTContext::GetCXXClassName(const CompilerType &type) { - if (!type) - return llvm::None; - - clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type)); - if (qual_type.isNull()) - return llvm::None; - - clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); - if (!cxx_record_decl) - return llvm::None; - - return std::string(cxx_record_decl->getIdentifier()->getNameStart()); -} - -bool ClangASTContext::IsCXXClassType(const CompilerType &type) { - if (!type) - return false; - - clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type)); - return !qual_type.isNull() && qual_type->getAsCXXRecordDecl() != nullptr; -} - -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 (!ClangUtil::IsClangType(type)) - return false; - - clang::QualType qual_type(ClangUtil::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; -} - -// 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; - 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 = - RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef}); - - const clang::Type::TypeClass type_class = qual_type->getTypeClass(); - switch (type_class) { - case clang::Type::Attributed: - return GetTypeInfo( - qual_type->getAs<clang::AttributedType>() - ->getModifiedType().getAsOpaquePtr(), - pointee_or_element_clang_type); - 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( - this, getASTContext().ObjCBuiltinClassTy.getAsOpaquePtr()); - builtin_type_flags |= eTypeIsPointer | eTypeIsObjC; - break; - - case clang::BuiltinType::ObjCSel: - if (pointee_or_element_clang_type) - pointee_or_element_clang_type->SetCompilerType( - this, getASTContext().CharTy.getAsOpaquePtr()); - 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( - this, qual_type->getPointeeType().getAsOpaquePtr()); - 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( - this, llvm::cast<clang::ArrayType>(qual_type.getTypePtr()) - ->getElementType() - .getAsOpaquePtr()); - 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::Enum: - if (pointee_or_element_clang_type) - pointee_or_element_clang_type->SetCompilerType( - this, llvm::cast<clang::EnumType>(qual_type) - ->getDecl() - ->getIntegerType() - .getAsOpaquePtr()); - return eTypeIsEnumeration | eTypeHasValue; - - 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( - this, llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()) - ->getPointeeType() - .getAsOpaquePtr()); - 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( - this, qual_type->getPointeeType().getAsOpaquePtr()); - 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( - this, qual_type->getPointeeType().getAsOpaquePtr()); - 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 | GetType(llvm::cast<clang::TypedefType>(qual_type) - ->getDecl() - ->getUnderlyingType()) - .GetTypeInfo(pointee_or_element_clang_type); - 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; - if (qual_type->getPointeeCXXRecordDecl()) - return lldb::eLanguageTypeC_plus_plus; - - clang::QualType pointee_type(qual_type->getPointeeType()); - if (pointee_type->getPointeeCXXRecordDecl()) - 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 GetType(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 = - RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef}); - - switch (qual_type->getTypeClass()) { - case clang::Type::Atomic: - case clang::Type::Auto: - case clang::Type::Decltype: - case clang::Type::Elaborated: - case clang::Type::Paren: - case clang::Type::TypeOf: - case clang::Type::TypeOfExpr: - llvm_unreachable("Handled in RemoveWrappingTypes!"); - 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::DependentVector: - 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::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::TemplateSpecialization: - break; - case clang::Type::DeducedTemplateSpecialization: - break; - case clang::Type::Pipe: - break; - - // pointer type decayed from an array or function type. - case clang::Type::Decayed: - break; - case clang::Type::Adjusted: - break; - case clang::Type::ObjCTypeParam: - break; - - case clang::Type::DependentAddressSpace: - break; - case clang::Type::MacroQualified: - 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(GetQualType(type)); - - const clang::Type *array_eletype = - qual_type.getTypePtr()->getArrayElementTypeNoTypeQual(); - - if (!array_eletype) - return CompilerType(); - - CompilerType element_type = GetType(clang::QualType(array_eletype, 0)); - - // TODO: the real stride will be >= this value.. find the real one! - if (stride) - if (Optional<uint64_t> size = element_type.GetByteSize(nullptr)) - *stride = *size; - - return element_type; - } - return CompilerType(); -} - -CompilerType ClangASTContext::GetArrayType(lldb::opaque_compiler_type_t type, - uint64_t size) { - if (type) { - clang::QualType qual_type(GetCanonicalQualType(type)); - clang::ASTContext &ast_ctx = getASTContext(); - if (size != 0) - return GetType(ast_ctx.getConstantArrayType( - qual_type, llvm::APInt(64, size), nullptr, - clang::ArrayType::ArraySizeModifier::Normal, 0)); - else - return GetType(ast_ctx.getIncompleteArrayType( - qual_type, clang::ArrayType::ArraySizeModifier::Normal, 0)); - } - - return CompilerType(); -} - -CompilerType -ClangASTContext::GetCanonicalType(lldb::opaque_compiler_type_t type) { - if (type) - return GetType(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 GetType( - 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 GetType(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 GetType(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 = RemoveWrappingTypes(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: { - const clang::ObjCObjectPointerType *objc_class_type = - qual_type->getAs<clang::ObjCObjectPointerType>(); - const clang::ObjCInterfaceType *objc_interface_type = - objc_class_type->getInterfaceType(); - if (objc_interface_type && - GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( - const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { - clang::ObjCInterfaceDecl *class_interface_decl = - objc_interface_type->getDecl(); - 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; - - 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 = RemoveWrappingTypes(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 = GetType(cxx_method_decl->getType()); - clang_decl = CompilerDecl(this, cxx_method_decl); - } - } - } - } - break; - - case clang::Type::ObjCObjectPointer: { - const clang::ObjCObjectPointerType *objc_class_type = - qual_type->getAs<clang::ObjCObjectPointerType>(); - const clang::ObjCInterfaceType *objc_interface_type = - objc_class_type->getInterfaceType(); - if (objc_interface_type && - GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( - const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { - clang::ObjCInterfaceDecl *class_interface_decl = - objc_interface_type->getDecl(); - 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; - - 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 GetType(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(ClangUtil::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 - - decl_ctx->addDecl(decl); - - // Get a uniqued clang::QualType for the typedef decl type - return ast->GetType(clang_ast.getTypedefType(decl)); - } - return CompilerType(); -} - -CompilerType -ClangASTContext::GetPointeeType(lldb::opaque_compiler_type_t type) { - if (type) { - clang::QualType qual_type(GetQualType(type)); - return GetType(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 GetType(getASTContext().getObjCObjectPointerType(qual_type)); - - default: - return GetType(getASTContext().getPointerType(qual_type)); - } - } - return CompilerType(); -} - -CompilerType -ClangASTContext::GetLValueReferenceType(lldb::opaque_compiler_type_t type) { - if (type) - return GetType(getASTContext().getLValueReferenceType(GetQualType(type))); - else - return CompilerType(); -} - -CompilerType -ClangASTContext::GetRValueReferenceType(lldb::opaque_compiler_type_t type) { - if (type) - return GetType(getASTContext().getRValueReferenceType(GetQualType(type))); - else - return CompilerType(); -} - -CompilerType ClangASTContext::GetAtomicType(lldb::opaque_compiler_type_t type) { - if (!type) - return CompilerType(); - return GetType(getASTContext().getAtomicType(GetQualType(type))); -} - -CompilerType -ClangASTContext::AddConstModifier(lldb::opaque_compiler_type_t type) { - if (type) { - clang::QualType result(GetQualType(type)); - result.addConst(); - return GetType(result); - } - return CompilerType(); -} - -CompilerType -ClangASTContext::AddVolatileModifier(lldb::opaque_compiler_type_t type) { - if (type) { - clang::QualType result(GetQualType(type)); - result.addVolatile(); - return GetType(result); - } - return CompilerType(); -} - -CompilerType -ClangASTContext::AddRestrictModifier(lldb::opaque_compiler_type_t type) { - if (type) { - clang::QualType result(GetQualType(type)); - result.addRestrict(); - return GetType(result); - } - 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)); - - clang::TagDecl *tdecl = nullptr; - if (!qual_type.isNull()) { - if (const clang::RecordType *rt = qual_type->getAs<clang::RecordType>()) - tdecl = rt->getDecl(); - if (const clang::EnumType *et = qual_type->getAs<clang::EnumType>()) - tdecl = et->getDecl(); - } - - // Check whether this declaration is an anonymous struct, union, or enum, - // hidden behind a typedef. If so, we try to check whether we have a - // typedef tag to attach to the original record declaration - if (tdecl && !tdecl->getIdentifier() && !tdecl->getTypedefNameForAnonDecl()) - tdecl->setTypedefNameForAnonDecl(decl); - - decl->setAccess(clang::AS_public); // TODO respect proper access specifier - - // Get a uniqued clang::QualType for the typedef decl type - return GetType(clang_ast.getTypedefType(decl)); - } - 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 GetType(typedef_type->getDecl()->getUnderlyingType()); - } - return CompilerType(); -} - -// Create related types using the current type's AST - -CompilerType ClangASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type) { - return ClangASTContext::GetBasicType(basic_type); -} -// Exploring the type - -const llvm::fltSemantics & -ClangASTContext::GetFloatTypeSemantics(size_t byte_size) { - clang::ASTContext &ast = getASTContext(); - const size_t bit_size = byte_size * 8; - if (bit_size == ast.getTypeSize(ast.FloatTy)) - return ast.getFloatTypeSemantics(ast.FloatTy); - else if (bit_size == ast.getTypeSize(ast.DoubleTy)) - return ast.getFloatTypeSemantics(ast.DoubleTy); - else if (bit_size == ast.getTypeSize(ast.LongDoubleTy)) - return ast.getFloatTypeSemantics(ast.LongDoubleTy); - else if (bit_size == ast.getTypeSize(ast.HalfTy)) - return ast.getFloatTypeSemantics(ast.HalfTy); - return llvm::APFloatBase::Bogus(); -} - -Optional<uint64_t> -ClangASTContext::GetBitSize(lldb::opaque_compiler_type_t type, - ExecutionContextScope *exe_scope) { - if (GetCompleteType(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)) - return getASTContext().getTypeSize(qual_type); - else - return None; - break; - - case clang::Type::ObjCInterface: - case clang::Type::ObjCObject: { - ExecutionContext exe_ctx(exe_scope); - Process *process = exe_ctx.GetProcessPtr(); - if (process) { - ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process); - if (objc_runtime) { - uint64_t bit_size = 0; - if (objc_runtime->GetTypeBitSize(GetType(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; - } - } - } - LLVM_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); - // Function types actually have a size of 0, that's not an error. - if (qual_type->isFunctionProtoType()) - return bit_size; - if (bit_size) - return bit_size; - } - } - return None; -} - -llvm::Optional<size_t> -ClangASTContext::GetTypeBitAlign(lldb::opaque_compiler_type_t type, - ExecutionContextScope *exe_scope) { - if (GetCompleteType(type)) - return getASTContext().getTypeAlign(GetQualType(type)); - return {}; -} - -lldb::Encoding ClangASTContext::GetEncoding(lldb::opaque_compiler_type_t type, - uint64_t &count) { - if (!type) - return lldb::eEncodingInvalid; - - count = 1; - clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); - - switch (qual_type->getTypeClass()) { - case clang::Type::Atomic: - case clang::Type::Auto: - case clang::Type::Decltype: - case clang::Type::Elaborated: - case clang::Type::Paren: - case clang::Type::Typedef: - case clang::Type::TypeOf: - case clang::Type::TypeOfExpr: - llvm_unreachable("Handled in RemoveWrappingTypes!"); - - 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::DependentVector: - 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::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::Char8: - 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: - return lldb::eEncodingUint; - - // Fixed point types. Note that they are currently ignored. - case clang::BuiltinType::ShortAccum: - case clang::BuiltinType::Accum: - case clang::BuiltinType::LongAccum: - case clang::BuiltinType::UShortAccum: - case clang::BuiltinType::UAccum: - case clang::BuiltinType::ULongAccum: - case clang::BuiltinType::ShortFract: - case clang::BuiltinType::Fract: - case clang::BuiltinType::LongFract: - case clang::BuiltinType::UShortFract: - case clang::BuiltinType::UFract: - case clang::BuiltinType::ULongFract: - case clang::BuiltinType::SatShortAccum: - case clang::BuiltinType::SatAccum: - case clang::BuiltinType::SatLongAccum: - case clang::BuiltinType::SatUShortAccum: - case clang::BuiltinType::SatUAccum: - case clang::BuiltinType::SatULongAccum: - case clang::BuiltinType::SatShortFract: - case clang::BuiltinType::SatFract: - case clang::BuiltinType::SatLongFract: - case clang::BuiltinType::SatUShortFract: - case clang::BuiltinType::SatUFract: - case clang::BuiltinType::SatULongFract: - break; - - case clang::BuiltinType::Half: - case clang::BuiltinType::Float: - case clang::BuiltinType::Float16: - case clang::BuiltinType::Float128: - 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::OCLImage1dRO: - case clang::BuiltinType::Kind::OCLImage1dWO: - case clang::BuiltinType::Kind::OCLImage1dRW: - case clang::BuiltinType::Kind::OCLImage1dArrayRO: - case clang::BuiltinType::Kind::OCLImage1dArrayWO: - case clang::BuiltinType::Kind::OCLImage1dArrayRW: - case clang::BuiltinType::Kind::OCLImage1dBufferRO: - case clang::BuiltinType::Kind::OCLImage1dBufferWO: - case clang::BuiltinType::Kind::OCLImage1dBufferRW: - case clang::BuiltinType::Kind::OCLImage2dRO: - case clang::BuiltinType::Kind::OCLImage2dWO: - case clang::BuiltinType::Kind::OCLImage2dRW: - case clang::BuiltinType::Kind::OCLImage2dArrayRO: - case clang::BuiltinType::Kind::OCLImage2dArrayWO: - case clang::BuiltinType::Kind::OCLImage2dArrayRW: - case clang::BuiltinType::Kind::OCLImage2dArrayDepthRO: - case clang::BuiltinType::Kind::OCLImage2dArrayDepthWO: - case clang::BuiltinType::Kind::OCLImage2dArrayDepthRW: - case clang::BuiltinType::Kind::OCLImage2dArrayMSAARO: - case clang::BuiltinType::Kind::OCLImage2dArrayMSAAWO: - case clang::BuiltinType::Kind::OCLImage2dArrayMSAARW: - case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRO: - case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthWO: - case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRW: - case clang::BuiltinType::Kind::OCLImage2dDepthRO: - case clang::BuiltinType::Kind::OCLImage2dDepthWO: - case clang::BuiltinType::Kind::OCLImage2dDepthRW: - case clang::BuiltinType::Kind::OCLImage2dMSAARO: - case clang::BuiltinType::Kind::OCLImage2dMSAAWO: - case clang::BuiltinType::Kind::OCLImage2dMSAARW: - case clang::BuiltinType::Kind::OCLImage2dMSAADepthRO: - case clang::BuiltinType::Kind::OCLImage2dMSAADepthWO: - case clang::BuiltinType::Kind::OCLImage2dMSAADepthRW: - case clang::BuiltinType::Kind::OCLImage3dRO: - case clang::BuiltinType::Kind::OCLImage3dWO: - case clang::BuiltinType::Kind::OCLImage3dRW: - case clang::BuiltinType::Kind::OCLQueue: - 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; - - case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload: - case clang::BuiltinType::OCLIntelSubgroupAVCImePayload: - case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload: - case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload: - case clang::BuiltinType::OCLIntelSubgroupAVCMceResult: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResult: - case clang::BuiltinType::OCLIntelSubgroupAVCRefResult: - case clang::BuiltinType::OCLIntelSubgroupAVCSicResult: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout: - case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout: - case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin: - case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: - break; - - case clang::BuiltinType::SveBool: - case clang::BuiltinType::SveInt8: - case clang::BuiltinType::SveInt16: - case clang::BuiltinType::SveInt32: - case clang::BuiltinType::SveInt64: - case clang::BuiltinType::SveUint8: - case clang::BuiltinType::SveUint16: - case clang::BuiltinType::SveUint32: - case clang::BuiltinType::SveUint64: - case clang::BuiltinType::SveFloat16: - case clang::BuiltinType::SveFloat32: - case clang::BuiltinType::SveFloat64: - 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 = GetType(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::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::TemplateSpecialization: - case clang::Type::DeducedTemplateSpecialization: - case clang::Type::Adjusted: - case clang::Type::Pipe: - break; - - // pointer type decayed from an array or function type. - case clang::Type::Decayed: - break; - case clang::Type::ObjCTypeParam: - break; - - case clang::Type::DependentAddressSpace: - break; - case clang::Type::MacroQualified: - 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 = RemoveWrappingTypes(GetCanonicalQualType(type)); - - switch (qual_type->getTypeClass()) { - case clang::Type::Atomic: - case clang::Type::Auto: - case clang::Type::Decltype: - case clang::Type::Elaborated: - case clang::Type::Paren: - case clang::Type::Typedef: - case clang::Type::TypeOf: - case clang::Type::TypeOfExpr: - llvm_unreachable("Handled in RemoveWrappingTypes!"); - 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::DependentVector: - 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::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::TemplateSpecialization: - case clang::Type::DeducedTemplateSpecialization: - case clang::Type::Adjusted: - case clang::Type::Pipe: - break; - - // pointer type decayed from an array or function type. - case clang::Type::Decayed: - break; - case clang::Type::ObjCTypeParam: - break; - - case clang::Type::DependentAddressSpace: - break; - case clang::Type::MacroQualified: - 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; -} - -static Optional<SymbolFile::ArrayInfo> -GetDynamicArrayInfo(ClangASTContext &ast, SymbolFile *sym_file, - clang::QualType qual_type, - const ExecutionContext *exe_ctx) { - if (qual_type->isIncompleteArrayType()) - if (auto *metadata = ast.GetMetadata(qual_type.getTypePtr())) - return sym_file->GetDynamicArrayInfoForUID(metadata->GetUserID(), - exe_ctx); - return llvm::None; -} - -uint32_t ClangASTContext::GetNumChildren(lldb::opaque_compiler_type_t type, - bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) { - if (!type) - return 0; - - uint32_t num_children = 0; - clang::QualType qual_type(RemoveWrappingTypes(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)) - 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 = - GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx); - // 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::IncompleteArray: - if (auto array_info = - GetDynamicArrayInfo(*this, GetSymbolFile(), qual_type, exe_ctx)) - // Only 1-dimensional arrays are supported. - num_children = array_info->element_orders.size() - ? array_info->element_orders.back() - : 0; - 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 = - GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx); - 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 = - GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx); - // 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; - - default: - break; - } - return num_children; -} - -CompilerType ClangASTContext::GetBuiltinTypeByName(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, - 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 = GetType(enum_decl->getIntegerType()); - - 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(RemoveWrappingTypes(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::ObjCObjectPointer: { - const clang::ObjCObjectPointerType *objc_class_type = - qual_type->getAs<clang::ObjCObjectPointerType>(); - const clang::ObjCInterfaceType *objc_interface_type = - objc_class_type->getInterfaceType(); - if (objc_interface_type && - GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( - const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { - clang::ObjCInterfaceDecl *class_interface_decl = - objc_interface_type->getDecl(); - 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(); - clang::Expr::EvalResult result; - if (bitfield_bit_size_expr && - bitfield_bit_size_expr->EvaluateAsInt(result, *ast)) { - llvm::APSInt bitfield_apsint = result.Val.getInt(); - *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(RemoveWrappingTypes(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(); - clang::Expr::EvalResult result; - if (bitfield_bit_size_expr && - bitfield_bit_size_expr->EvaluateAsInt(result, - getASTContext())) { - llvm::APSInt bitfield_apsint = result.Val.getInt(); - *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue(); - } - } - } - if (is_bitfield_ptr) - *is_bitfield_ptr = is_bitfield; - - return GetType(field->getType()); - } - } - } - break; - - case clang::Type::ObjCObjectPointer: { - const clang::ObjCObjectPointerType *objc_class_type = - qual_type->getAs<clang::ObjCObjectPointerType>(); - const clang::ObjCInterfaceType *objc_interface_type = - objc_class_type->getInterfaceType(); - if (objc_interface_type && - GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( - const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { - clang::ObjCInterfaceDecl *class_interface_decl = - objc_interface_type->getDecl(); - if (class_interface_decl) { - 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; - - default: - break; - } - return CompilerType(); -} - -uint32_t -ClangASTContext::GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) { - uint32_t count = 0; - clang::QualType qual_type = RemoveWrappingTypes(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; - - default: - break; - } - return count; -} - -uint32_t -ClangASTContext::GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) { - uint32_t count = 0; - clang::QualType qual_type = RemoveWrappingTypes(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; - - 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 = RemoveWrappingTypes(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 GetType(base_class->getType()); - } - } - } - } - 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 GetType(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 GetType(getASTContext().getObjCInterfaceType( - superclass_interface_decl)); - } - } - } - } - break; - - 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 = RemoveWrappingTypes(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->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 GetType(base_class->getType()); - } - } - } - } - break; - - 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 = RemoveWrappingTypes(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::OCLImage1dRO: - case clang::BuiltinType::OCLImage1dWO: - case clang::BuiltinType::OCLImage1dRW: - case clang::BuiltinType::OCLImage1dArrayRO: - case clang::BuiltinType::OCLImage1dArrayWO: - case clang::BuiltinType::OCLImage1dArrayRW: - case clang::BuiltinType::OCLImage1dBufferRO: - case clang::BuiltinType::OCLImage1dBufferWO: - case clang::BuiltinType::OCLImage1dBufferRW: - case clang::BuiltinType::OCLImage2dRO: - case clang::BuiltinType::OCLImage2dWO: - case clang::BuiltinType::OCLImage2dRW: - case clang::BuiltinType::OCLImage2dArrayRO: - case clang::BuiltinType::OCLImage2dArrayWO: - case clang::BuiltinType::OCLImage2dArrayRW: - case clang::BuiltinType::OCLImage3dRO: - case clang::BuiltinType::OCLImage3dWO: - case clang::BuiltinType::OCLImage3dRW: - 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::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(); - - auto get_exe_scope = [&exe_ctx]() { - return exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr; - }; - - clang::QualType parent_qual_type( - RemoveWrappingTypes(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, exe_ctx); - int32_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 GetType(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)) - 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) { - clang::VTableContextBase *vtable_ctx = - getASTContext().getVTableContext(); - if (vtable_ctx) - handled = GetVBaseBitOffset(*vtable_ctx, *valobj, - record_layout, cxx_record_decl, - base_class_decl, bit_offset); - } - 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 = GetType(base_class->getType()); - child_name = base_class_clang_type.GetTypeName().AsCString(""); - Optional<uint64_t> size = - base_class_clang_type.GetBitSize(get_exe_scope()); - if (!size) - return {}; - uint64_t base_class_clang_type_bit_size = *size; - - // 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()); - - // Figure out the type byte size (field_type_info.first) and - // alignment (field_type_info.second) from the AST context. - CompilerType field_clang_type = GetType(field->getType()); - assert(field_idx < record_layout.getFieldCount()); - Optional<uint64_t> size = - field_clang_type.GetByteSize(get_exe_scope()); - if (!size) - return {}; - child_byte_size = *size; - const uint32_t child_bit_size = child_byte_size * 8; - - // Figure out the field offset within the current struct/union/class - // type - bit_offset = record_layout.getFieldOffset(field_idx); - if (FieldIsBitfield(*field, child_bitfield_bit_size)) { - child_bitfield_bit_offset = bit_offset % child_bit_size; - const uint32_t child_bit_offset = - bit_offset - child_bitfield_bit_offset; - child_byte_offset = child_bit_offset / 8; - } else { - child_byte_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 = - GetType(getASTContext().getObjCInterfaceType( - superclass_interface_decl)); - if (base_class_clang_type.GetNumChildren(omit_empty_base_classes, - exe_ctx) > 0) { - if (idx == 0) { - clang::QualType ivar_qual_type( - getASTContext().getObjCInterfaceType( - superclass_interface_decl)); - - child_name.assign( - superclass_interface_decl->getNameAsString()); - - 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 GetType(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()); - - 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 = - ObjCLanguageRuntime::Get(*process); - if (objc_runtime != nullptr) { - CompilerType parent_ast_type = GetType(parent_qual_type); - child_byte_offset = objc_runtime->GetByteOffsetForIvar( - parent_ast_type, ivar_decl->getNameAsString().c_str()); - } - } - - // Setting this to INT32_MAX to make sure we don't compute it - // twice... - bit_offset = INT32_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 (FieldIsBitfield(ivar_decl, child_bitfield_bit_size)) { - if (bit_offset == INT32_MAX) - bit_offset = interface_layout.getFieldOffset( - child_idx - superclass_idx); - - child_bitfield_bit_offset = bit_offset % 8; - } - return GetType(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() : nullptr; - 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()) { - if (Optional<uint64_t> size = - pointee_clang_type.GetByteSize(get_exe_scope())) { - child_byte_size = *size; - 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 = GetType(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); - if (Optional<uint64_t> size = - element_type.GetByteSize(get_exe_scope())) { - child_byte_size = *size; - 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 = GetType(array->getElementType()); - if (element_type.GetCompleteType()) { - child_name = llvm::formatv("[{0}]", idx); - if (Optional<uint64_t> size = - element_type.GetByteSize(get_exe_scope())) { - child_byte_size = *size; - child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; - return element_type; - } - } - } - } - break; - - case clang::Type::Pointer: { - 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() : nullptr; - if (parent_name) { - child_name.assign(1, '*'); - child_name += parent_name; - } - - // We have a pointer to an simple type - if (idx == 0) { - if (Optional<uint64_t> size = - pointee_clang_type.GetByteSize(get_exe_scope())) { - child_byte_size = *size; - 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 = - GetType(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() : nullptr; - if (parent_name) { - child_name.assign(1, '&'); - child_name += parent_name; - } - - // We have a pointer to an simple type - if (idx == 0) { - if (Optional<uint64_t> size = - pointee_clang_type.GetByteSize(get_exe_scope())) { - child_byte_size = *size; - child_byte_offset = 0; - return pointee_clang_type; - } - } - } - } - break; - - 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) { - 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 = RemoveWrappingTypes(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 = GetType(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 = - GetType(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 = GetType( - 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 = GetType(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; - - 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 = RemoveWrappingTypes(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)) - continue; - - CompilerType base_class_clang_type = GetType(base_class->getType()); - std::string base_class_type_name( - base_class_clang_type.GetTypeName().AsCString("")); - if (base_class_type_name == name) - 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 = GetType( - 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 = GetType(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 = GetType(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; - - default: - break; - } - } - return UINT32_MAX; -} - -size_t -ClangASTContext::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) { - if (!type) - return 0; - - clang::QualType qual_type = RemoveWrappingTypes(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; - - default: - break; - } - - return 0; -} - -const clang::ClassTemplateSpecializationDecl * -ClangASTContext::GetAsTemplateSpecialization( - lldb::opaque_compiler_type_t type) { - if (!type) - return nullptr; - - clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); - const clang::Type::TypeClass type_class = qual_type->getTypeClass(); - switch (type_class) { - case clang::Type::Record: { - if (! GetCompleteType(type)) - return nullptr; - const clang::CXXRecordDecl *cxx_record_decl = - qual_type->getAsCXXRecordDecl(); - if (!cxx_record_decl) - return nullptr; - return llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>( - cxx_record_decl); - } - - default: - return nullptr; - } -} - -lldb::TemplateArgumentKind -ClangASTContext::GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, - size_t arg_idx) { - const clang::ClassTemplateSpecializationDecl *template_decl = - GetAsTemplateSpecialization(type); - if (! template_decl || arg_idx >= template_decl->getTemplateArgs().size()) - return eTemplateArgumentKindNull; - - switch (template_decl->getTemplateArgs()[arg_idx].getKind()) { - case clang::TemplateArgument::Null: - return eTemplateArgumentKindNull; - - case clang::TemplateArgument::NullPtr: - return eTemplateArgumentKindNullPtr; - - case clang::TemplateArgument::Type: - return eTemplateArgumentKindType; - - case clang::TemplateArgument::Declaration: - return eTemplateArgumentKindDeclaration; - - case clang::TemplateArgument::Integral: - return eTemplateArgumentKindIntegral; - - case clang::TemplateArgument::Template: - return eTemplateArgumentKindTemplate; - - case clang::TemplateArgument::TemplateExpansion: - return eTemplateArgumentKindTemplateExpansion; - - case clang::TemplateArgument::Expression: - return eTemplateArgumentKindExpression; - - case clang::TemplateArgument::Pack: - return eTemplateArgumentKindPack; - } - llvm_unreachable("Unhandled clang::TemplateArgument::ArgKind"); -} - -CompilerType -ClangASTContext::GetTypeTemplateArgument(lldb::opaque_compiler_type_t type, - size_t idx) { - const clang::ClassTemplateSpecializationDecl *template_decl = - GetAsTemplateSpecialization(type); - if (!template_decl || idx >= template_decl->getTemplateArgs().size()) - return CompilerType(); - - const clang::TemplateArgument &template_arg = - template_decl->getTemplateArgs()[idx]; - if (template_arg.getKind() != clang::TemplateArgument::Type) - return CompilerType(); - - return GetType(template_arg.getAsType()); -} - -Optional<CompilerType::IntegralTemplateArgument> -ClangASTContext::GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, - size_t idx) { - const clang::ClassTemplateSpecializationDecl *template_decl = - GetAsTemplateSpecialization(type); - if (! template_decl || idx >= template_decl->getTemplateArgs().size()) - return llvm::None; - - const clang::TemplateArgument &template_arg = - template_decl->getTemplateArgs()[idx]; - if (template_arg.getKind() != clang::TemplateArgument::Integral) - return llvm::None; - - return { - {template_arg.getAsIntegral(), GetType(template_arg.getIntegralType())}}; -} - -CompilerType ClangASTContext::GetTypeForFormatters(void *type) { - if (type) - return ClangUtil::RemoveFastQualifiers(CompilerType(this, type)); - return CompilerType(); -} - -clang::EnumDecl *ClangASTContext::GetAsEnumDecl(const CompilerType &type) { - const clang::EnumType *enutype = - llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type)); - if (enutype) - return enutype->getDecl(); - return nullptr; -} - -clang::RecordDecl *ClangASTContext::GetAsRecordDecl(const CompilerType &type) { - const clang::RecordType *record_type = - llvm::dyn_cast<clang::RecordType>(ClangUtil::GetCanonicalQualType(type)); - if (record_type) - return record_type->getDecl(); - return nullptr; -} - -clang::TagDecl *ClangASTContext::GetAsTagDecl(const CompilerType &type) { - return ClangUtil::GetAsTagDecl(type); -} - -clang::TypedefNameDecl * -ClangASTContext::GetAsTypedefDecl(const CompilerType &type) { - const clang::TypedefType *typedef_type = - llvm::dyn_cast<clang::TypedefType>(ClangUtil::GetQualType(type)); - if (typedef_type) - return typedef_type->getDecl(); - return nullptr; -} - -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>( - ClangUtil::GetCanonicalQualType(type)); - if (objc_class_type) - return objc_class_type->getInterface(); - return nullptr; -} - -clang::FieldDecl *ClangASTContext::AddFieldToRecordType( - const CompilerType &type, llvm::StringRef 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::IdentifierInfo *ident = nullptr; - if (!name.empty()) - ident = &clang_ast.Idents.get(name); - - 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(), - ident, // Identifier - ClangUtil::GetQualType(field_clang_type), // Field type - nullptr, // TInfo * - bit_width, // BitWidth - false, // Mutable - clang::ICIS_NoInit); // HasInit - - if (name.empty()) { - // 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(), - ident, // Identifier - ClangUtil::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)) { - size_t 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, llvm::StringRef name, - const CompilerType &var_type, AccessType access) { - 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) - return nullptr; - - clang::VarDecl *var_decl = nullptr; - clang::IdentifierInfo *ident = nullptr; - if (!name.empty()) - ident = &ast->getASTContext().Idents.get(name); - - var_decl = clang::VarDecl::Create( - ast->getASTContext(), // ASTContext & - record_decl, // DeclContext * - clang::SourceLocation(), // clang::SourceLocation StartLoc - clang::SourceLocation(), // clang::SourceLocation IdLoc - ident, // clang::IdentifierInfo * - ClangUtil::GetQualType(var_type), // Variable clang::QualType - nullptr, // TypeSourceInfo * - clang::SC_Static); // StorageClass - if (!var_decl) - return nullptr; - - 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, llvm::StringRef name, - const char *mangled_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.empty()) - 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(ClangUtil::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 - - const clang::ExplicitSpecifier explicit_spec( - nullptr /*expr*/, is_explicit - ? clang::ExplicitSpecKind::ResolvedTrue - : clang::ExplicitSpecKind::ResolvedFalse); - if (name.startswith("~")) { - 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, - ConstexprSpecKind::CSK_unspecified); - 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 * - explicit_spec, is_inline, is_artificial, CSK_unspecified); - 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. - const bool is_method = true; - if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount( - is_method, 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, CSK_unspecified, 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, explicit_spec, CSK_unspecified, 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, CSK_unspecified, 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())); - - if (mangled_name != nullptr) { - cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( - getASTContext(), mangled_name, /*literal=*/false)); - } - - // 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 - - return cxx_method_decl; -} - -void ClangASTContext::AddMethodOverridesForCXXRecordType( - lldb::opaque_compiler_type_t type) { - if (auto *record = GetAsCXXRecordDecl(type)) - for (auto *method : record->methods()) - addOverridesForMethod(method); -} - -#pragma mark C++ Base Classes - -std::unique_ptr<clang::CXXBaseSpecifier> -ClangASTContext::CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type, - AccessType access, bool is_virtual, - bool base_of_class) { - if (!type) - return nullptr; - - return std::make_unique<clang::CXXBaseSpecifier>( - clang::SourceRange(), is_virtual, base_of_class, - ClangASTContext::ConvertAccessTypeToAccessSpecifier(access), - getASTContext().getTrivialTypeSourceInfo(GetQualType(type)), - clang::SourceLocation()); -} - -bool ClangASTContext::TransferBaseClasses( - lldb::opaque_compiler_type_t type, - std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases) { - if (!type) - return false; - clang::CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl(type); - if (!cxx_record_decl) - return false; - std::vector<clang::CXXBaseSpecifier *> raw_bases; - raw_bases.reserve(bases.size()); - - // Clang will make a copy of them, so it's ok that we pass pointers that we're - // about to destroy. - for (auto &b : bases) - raw_bases.push_back(b.get()); - cxx_record_decl->setBases(raw_bases.data(), raw_bases.size()); - return true; -} - -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) - return false; - - 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 = ast->GetType(ivar_decl->getType()); - - if (!class_interface_decl || !property_clang_type_to_access.IsValid()) - return false; - - clang::TypeSourceInfo *prop_type_source; - if (ivar_decl) - prop_type_source = clang_ast.getTrivialTypeSourceInfo(ivar_decl->getType()); - else - prop_type_source = clang_ast.getTrivialTypeSourceInfo( - ClangUtil::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() - : ClangUtil::GetQualType(property_clang_type), - prop_type_source); - - if (!property_decl) - return false; - - if (metadata) - ast->SetMetadata(property_decl, *metadata); - - class_interface_decl->addDecl(property_decl); - - clang::Selector setter_sel, getter_sel; - - if (property_setter_name) { - 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); - 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); - setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident); - } - property_decl->setSetterName(setter_sel); - property_decl->setPropertyAttributes(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(ObjCPropertyDecl::OBJC_PR_getter); - - if (ivar_decl) - property_decl->setPropertyIvarDecl(ivar_decl); - - if (property_attributes & DW_APPLE_PROPERTY_readonly) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); - if (property_attributes & DW_APPLE_PROPERTY_readwrite) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); - if (property_attributes & DW_APPLE_PROPERTY_assign) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); - if (property_attributes & DW_APPLE_PROPERTY_retain) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); - if (property_attributes & DW_APPLE_PROPERTY_copy) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); - if (property_attributes & DW_APPLE_PROPERTY_nonatomic) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); - if (property_attributes & ObjCPropertyDecl::OBJC_PR_nullability) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability); - if (property_attributes & ObjCPropertyDecl::OBJC_PR_null_resettable) - property_decl->setPropertyAttributes( - ObjCPropertyDecl::OBJC_PR_null_resettable); - if (property_attributes & ObjCPropertyDecl::OBJC_PR_class) - property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class); - - const bool isInstance = - (property_attributes & ObjCPropertyDecl::OBJC_PR_class) == 0; - - clang::ObjCMethodDecl *getter = nullptr; - if (!getter_sel.isNull()) - getter = isInstance ? class_interface_decl->lookupInstanceMethod(getter_sel) - : class_interface_decl->lookupClassMethod(getter_sel); - if (!getter_sel.isNull() && !getter) { - const bool isVariadic = false; - const bool isPropertyAccessor = false; - const bool isSynthesizedAccessorStub = false; - const bool isImplicitlyDeclared = true; - const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = - clang::ObjCMethodDecl::None; - const bool HasRelatedResultType = false; - - getter = clang::ObjCMethodDecl::Create( - clang_ast, clang::SourceLocation(), clang::SourceLocation(), getter_sel, - ClangUtil::GetQualType(property_clang_type_to_access), nullptr, - class_interface_decl, isInstance, isVariadic, isPropertyAccessor, - isSynthesizedAccessorStub, isImplicitlyDeclared, isDefined, impControl, - HasRelatedResultType); - - if (getter) { - if (metadata) - ast->SetMetadata(getter, *metadata); - - getter->setMethodParams(clang_ast, llvm::ArrayRef<clang::ParmVarDecl *>(), - llvm::ArrayRef<clang::SourceLocation>()); - class_interface_decl->addDecl(getter); - } - } - if (getter) { - getter->setPropertyAccessor(true); - property_decl->setGetterMethodDecl(getter); - } - - clang::ObjCMethodDecl *setter = nullptr; - setter = isInstance ? class_interface_decl->lookupInstanceMethod(setter_sel) - : class_interface_decl->lookupClassMethod(setter_sel); - if (!setter_sel.isNull() && !setter) { - clang::QualType result_type = clang_ast.VoidTy; - const bool isVariadic = false; - const bool isPropertyAccessor = true; - const bool isSynthesizedAccessorStub = false; - const bool isImplicitlyDeclared = true; - const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = - clang::ObjCMethodDecl::None; - const bool HasRelatedResultType = false; - - setter = clang::ObjCMethodDecl::Create( - clang_ast, clang::SourceLocation(), clang::SourceLocation(), setter_sel, - result_type, nullptr, class_interface_decl, isInstance, isVariadic, - isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared, - isDefined, impControl, HasRelatedResultType); - - if (setter) { - if (metadata) - ast->SetMetadata(setter, *metadata); - - llvm::SmallVector<clang::ParmVarDecl *, 1> params; - params.push_back(clang::ParmVarDecl::Create( - clang_ast, setter, clang::SourceLocation(), clang::SourceLocation(), - nullptr, // anonymous - ClangUtil::GetQualType(property_clang_type_to_access), nullptr, - clang::SC_Auto, nullptr)); - - setter->setMethodParams(clang_ast, - llvm::ArrayRef<clang::ParmVarDecl *>(params), - llvm::ArrayRef<clang::SourceLocation>()); - - class_interface_decl->addDecl(setter); - } - } - if (setter) { - setter->setPropertyAccessor(true); - property_decl->setSetterMethodDecl(setter); - } - - return true; -} - -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, bool is_variadic, bool is_objc_direct_call) { - 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(ClangUtil::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; - - const bool isInstance = (name[0] == '-'); - const bool isVariadic = is_variadic; - const bool isPropertyAccessor = false; - const bool isSynthesizedAccessorStub = false; - /// Force this to true because we don't have source locations. - const bool isImplicitlyDeclared = true; - const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = - clang::ObjCMethodDecl::None; - const bool HasRelatedResultType = false; - - 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, - lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type)), isInstance, - isVariadic, isPropertyAccessor, isSynthesizedAccessorStub, - isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); - - 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>()); - } - - if (is_objc_direct_call) { - // Add a the objc_direct attribute to the declaration we generate that - // we generate a direct method call for this ObjCMethodDecl. - objc_method_decl->addAttr( - clang::ObjCDirectAttr::CreateImplicit(ast, SourceLocation())); - // Usually Sema is creating implicit parameters (e.g., self) when it - // parses the method. We don't have a parsing Sema when we build our own - // AST here so we manually need to create these implicit parameters to - // make the direct call code generation happy. - objc_method_decl->createImplicitParams(ast, class_interface_decl); - } - - class_interface_decl->addDecl(objc_method_decl); - -#ifdef LLDB_CONFIGURATION_DEBUG - VerifyDecl(objc_method_decl); -#endif - - return objc_method_decl; -} - -bool ClangASTContext::SetHasExternalStorage(lldb::opaque_compiler_type_t type, - bool has_extern) { - if (!type) - return false; - - clang::QualType qual_type(RemoveWrappingTypes(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; - - default: - break; - } - return false; -} - -#pragma mark TagDecl - -bool ClangASTContext::StartTagDeclarationDefinition(const CompilerType &type) { - clang::QualType qual_type(ClangUtil::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(ClangUtil::GetQualType(type)); - if (qual_type.isNull()) - return false; - - // Make sure we use the same methodology as - // ClangASTContext::StartTagDeclarationDefinition() as to how we start/end - // the definition. - const clang::TagType *tag_type = qual_type->getAs<clang::TagType>(); - if (tag_type) { - clang::TagDecl *tag_decl = tag_type->getDecl(); - - if (auto *cxx_record_decl = llvm::dyn_cast<CXXRecordDecl>(tag_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; - } - } - - const clang::EnumType *enutype = qual_type->getAs<clang::EnumType>(); - - if (!enutype) - return false; - clang::EnumDecl *enum_decl = enutype->getDecl(); - - if (enum_decl->isCompleteDefinition()) - return true; - - 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. - - QualType integer_type(enum_decl->getIntegerType()); - if (!integer_type.isNull()) { - 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; -} - -clang::EnumConstantDecl *ClangASTContext::AddEnumerationValueToEnumerationType( - const CompilerType &enum_type, const Declaration &decl, const char *name, - const llvm::APSInt &value) { - - if (!enum_type || ConstString(name).IsEmpty()) - return nullptr; - - lldbassert(enum_type.GetTypeSystem() == static_cast<TypeSystem *>(this)); - - lldb::opaque_compiler_type_t enum_opaque_compiler_type = - enum_type.GetOpaqueQualType(); - - if (!enum_opaque_compiler_type) - return nullptr; - - clang::QualType enum_qual_type( - GetCanonicalQualType(enum_opaque_compiler_type)); - - const clang::Type *clang_type = enum_qual_type.getTypePtr(); - - if (!clang_type) - return nullptr; - - const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(clang_type); - - if (!enutype) - return nullptr; - - clang::EnumConstantDecl *enumerator_decl = clang::EnumConstantDecl::Create( - getASTContext(), enutype->getDecl(), clang::SourceLocation(), - name ? &getASTContext().Idents.get(name) : nullptr, // Identifier - clang::QualType(enutype, 0), nullptr, value); - - if (!enumerator_decl) - return nullptr; - - enutype->getDecl()->addDecl(enumerator_decl); - -#ifdef LLDB_CONFIGURATION_DEBUG - VerifyDecl(enumerator_decl); -#endif - - return enumerator_decl; -} - -clang::EnumConstantDecl *ClangASTContext::AddEnumerationValueToEnumerationType( - const CompilerType &enum_type, const Declaration &decl, const char *name, - int64_t enum_value, uint32_t enum_value_bit_size) { - CompilerType underlying_type = - GetEnumerationIntegerType(enum_type.GetOpaqueQualType()); - bool is_signed = false; - underlying_type.IsIntegerType(is_signed); - - llvm::APSInt value(enum_value_bit_size, is_signed); - value = enum_value; - - return AddEnumerationValueToEnumerationType(enum_type, decl, name, value); -} - -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 GetType(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 ast->GetType(ast->getASTContext().getMemberPointerType( - ClangUtil::GetQualType(pointee_type), - ClangUtil::GetQualType(type).getTypePtr())); - } - return CompilerType(); -} - -// Dumping types -#define DEPTH_INCREMENT 2 - -#ifndef NDEBUG -LLVM_DUMP_METHOD void -ClangASTContext::dump(lldb::opaque_compiler_type_t type) const { - if (!type) - return; - clang::QualType qual_type(GetQualType(type)); - qual_type.dump(); -} -#endif - -void ClangASTContext::Dump(Stream &s) { - Decl *tu = Decl::castFromDeclContext(GetTranslationUnitDecl()); - tu->dump(s.AsRawOstream()); -} - -void ClangASTContext::DumpFromSymbolFile(Stream &s, - llvm::StringRef symbol_name) { - SymbolFile *symfile = GetSymbolFile(); - - if (!symfile) - return; - - lldb_private::TypeList type_list; - symfile->GetTypes(nullptr, eTypeClassAny, type_list); - size_t ntypes = type_list.GetSize(); - - for (size_t i = 0; i < ntypes; ++i) { - TypeSP type = type_list.GetTypeAtIndex(i); - - if (!symbol_name.empty()) - if (symbol_name != type->GetName().GetStringRef()) - continue; - - s << type->GetName().AsCString() << "\n"; - - CompilerType full_type = type->GetFullCompilerType(); - if (clang::TagDecl *tag_decl = GetAsTagDecl(full_type)) { - tag_decl->dump(s.AsRawOstream()); - continue; - } - if (clang::TypedefNameDecl *typedef_decl = GetAsTypedefDecl(full_type)) { - typedef_decl->dump(s.AsRawOstream()); - continue; - } - if (auto *objc_obj = llvm::dyn_cast<clang::ObjCObjectType>( - ClangUtil::GetQualType(full_type).getTypePtr())) { - if (clang::ObjCInterfaceDecl *interface_decl = objc_obj->getInterface()) { - interface_decl->dump(s.AsRawOstream()); - continue; - } - } - GetCanonicalQualType(full_type.GetOpaqueQualType()).dump(s.AsRawOstream()); - } -} - -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 && !ClangASTContext::RecordHasFields(base_class_decl)) - 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->Format("\n{0}{1}", llvm::fmt_repeat(" ", depth + DEPTH_INCREMENT), - base_class_type_name); - - clang::TypeInfo base_class_type_info = - getASTContext().getTypeInfo(base_class_qual_type); - - // Dump the value of the member - CompilerType base_clang_type = GetType(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 (FieldIsBitfield(*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 = GetType(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('"'); - DumpDataExtractor(data, s, data_byte_offset, lldb::eFormatChar, - element_byte_size, element_count, UINT32_MAX, - LLDB_INVALID_ADDRESS, 0, 0); - s->PutChar('"'); - return; - } else { - CompilerType element_clang_type = GetType(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 = GetType(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 = GetType(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 = GetType(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 = GetType(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. - DumpDataExtractor(data, 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; - } -} - -static bool DumpEnumValue(const clang::QualType &qual_type, Stream *s, - const DataExtractor &data, lldb::offset_t byte_offset, - size_t byte_size, uint32_t bitfield_bit_offset, - uint32_t bitfield_bit_size) { - const clang::EnumType *enutype = - llvm::cast<clang::EnumType>(qual_type.getTypePtr()); - const clang::EnumDecl *enum_decl = enutype->getDecl(); - assert(enum_decl); - lldb::offset_t offset = byte_offset; - const uint64_t enum_svalue = data.GetMaxS64Bitfield( - &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); - bool can_be_bitfield = true; - uint64_t covered_bits = 0; - int num_enumerators = 0; - - // Try to find an exact match for the value. - // At the same time, we're applying a heuristic to determine whether we want - // to print this enum as a bitfield. We're likely dealing with a bitfield if - // every enumrator is either a one bit value or a superset of the previous - // enumerators. Also 0 doesn't make sense when the enumerators are used as - // flags. - for (auto enumerator : enum_decl->enumerators()) { - uint64_t val = enumerator->getInitVal().getSExtValue(); - val = llvm::SignExtend64(val, 8*byte_size); - if (llvm::countPopulation(val) != 1 && (val & ~covered_bits) != 0) - can_be_bitfield = false; - covered_bits |= val; - ++num_enumerators; - if (val == enum_svalue) { - // Found an exact match, that's all we need to do. - s->PutCString(enumerator->getNameAsString()); - return true; - } - } - - // Unsigned values make more sense for flags. - offset = byte_offset; - const uint64_t enum_uvalue = data.GetMaxU64Bitfield( - &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); - - // No exact match, but we don't think this is a bitfield. Print the value as - // decimal. - if (!can_be_bitfield) { - if (qual_type->isSignedIntegerOrEnumerationType()) - s->Printf("%" PRIi64, enum_svalue); - else - s->Printf("%" PRIu64, enum_uvalue); - return true; - } - - uint64_t remaining_value = enum_uvalue; - std::vector<std::pair<uint64_t, llvm::StringRef>> values; - values.reserve(num_enumerators); - for (auto enumerator : enum_decl->enumerators()) - if (auto val = enumerator->getInitVal().getZExtValue()) - values.emplace_back(val, enumerator->getName()); - - // Sort in reverse order of the number of the population count, so that in - // `enum {A, B, ALL = A|B }` we visit ALL first. Use a stable sort so that - // A | C where A is declared before C is displayed in this order. - std::stable_sort(values.begin(), values.end(), [](const auto &a, const auto &b) { - return llvm::countPopulation(a.first) > llvm::countPopulation(b.first); - }); - - for (const auto &val : values) { - if ((remaining_value & val.first) != val.first) - continue; - remaining_value &= ~val.first; - s->PutCString(val.second); - if (remaining_value) - s->PutCString(" | "); - } - - // If there is a remainder that is not covered by the value, print it as hex. - if (remaining_value) - s->Printf("0x%" PRIx64, remaining_value); - - return true; -} - -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(); - - if (type_class == clang::Type::Elaborated) { - qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType(); - return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size, - bitfield_bit_size, bitfield_bit_offset, exe_scope); - } - - switch (type_class) { - case clang::Type::Typedef: { - clang::QualType typedef_qual_type = - llvm::cast<clang::TypedefType>(qual_type) - ->getDecl() - ->getUnderlyingType(); - CompilerType typedef_clang_type = GetType(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)) - return DumpEnumValue(qual_type, s, data, byte_offset, byte_size, - bitfield_bit_offset, bitfield_bit_size); - // format was not enum, just fall through and dump the value as - // requested.... - LLVM_FALLTHROUGH; - - 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 DumpDataExtractor(data, s, byte_offset, format, byte_size, - item_count, UINT32_MAX, LLDB_INVALID_ADDRESS, - bitfield_bit_size, bitfield_bit_offset, - exe_scope); - } - break; - } - } - return false; -} - -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); - - DataExtractor cstr_data(&buf.front(), buf.size(), - process->GetByteOrder(), 4); - buf.back() = '\0'; - size_t bytes_read; - size_t total_cstr_len = 0; - Status 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(" \""); - DumpDataExtractor(cstr_data, 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); - - CompilerType ct(this, type); - const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr(); - ClangASTMetadata *metadata = GetMetadata(clang_type); - if (metadata) { - metadata->Dump(&s); - } -} - -void ClangASTContext::DumpTypeDescription(lldb::opaque_compiler_type_t type, - Stream *s) { - if (type) { - clang::QualType qual_type = - RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef}); - - 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); - } - } - } break; - - 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); - } - } - } - - if (buf.size() > 0) { - s->Write(buf.data(), buf.size()); - } - } -} - -void ClangASTContext::DumpTypeName(const CompilerType &type) { - if (ClangUtil::IsClangType(type)) { - clang::QualType qual_type( - ClangUtil::GetCanonicalQualType(ClangUtil::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 nullptr; -} - -void ClangASTContext::CompleteTagDecl(clang::TagDecl *decl) { - SymbolFile *sym_file = GetSymbolFile(); - if (sym_file) { - CompilerType clang_type = GetTypeForDecl(decl); - if (clang_type) - sym_file->CompleteType(clang_type); - } -} - -void ClangASTContext::CompleteObjCInterfaceDecl( - clang::ObjCInterfaceDecl *decl) { - SymbolFile *sym_file = 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_up) - m_dwarf_ast_parser_up.reset(new DWARFASTParserClang(*this)); - return m_dwarf_ast_parser_up.get(); -} - -PDBASTParser *ClangASTContext::GetPDBParser() { - if (!m_pdb_ast_parser_up) - m_pdb_ast_parser_up.reset(new PDBASTParser(*this)); - return m_pdb_ast_parser_up.get(); -} - -bool ClangASTContext::LayoutRecordType( - 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) { - lldb_private::ClangASTImporter *importer = nullptr; - if (m_dwarf_ast_parser_up) - importer = &m_dwarf_ast_parser_up->GetClangASTImporter(); - if (!importer && m_pdb_ast_parser_up) - importer = &m_pdb_ast_parser_up->GetClangASTImporter(); - if (!importer) - return false; - - return importer->LayoutRecordType(record_decl, bit_size, alignment, - field_offsets, base_offsets, vbase_offsets); -} - -// CompilerDecl override functions - -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 CreateDeclContext(((clang::Decl *)opaque_decl)->getDeclContext()); - return CompilerDeclContext(); -} - -CompilerType ClangASTContext::DeclGetFunctionReturnType(void *opaque_decl) { - if (clang::FunctionDecl *func_decl = - llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl)) - return GetType(func_decl->getReturnType()); - if (clang::ObjCMethodDecl *objc_method = - llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl *)opaque_decl)) - return GetType(objc_method->getReturnType()); - 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 GetType(var_decl->getOriginalType()); - } - } else if (clang::ObjCMethodDecl *objc_method = - llvm::dyn_cast<clang::ObjCMethodDecl>( - (clang::Decl *)opaque_decl)) { - if (idx < objc_method->param_size()) - return GetType(objc_method->parameters()[idx]->getOriginalType()); - } - return CompilerType(); -} - -// CompilerDeclContext functions - -std::vector<CompilerDecl> ClangASTContext::DeclContextFindDeclByName( - void *opaque_decl_ctx, ConstString name, const bool ignore_using_decls) { - 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( - CreateDeclContext(it->second)); - - for (clang::Decl *child : it->second->decls()) { - if (clang::UsingDirectiveDecl *ud = - llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) { - if (ignore_using_decls) - continue; - 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)) { - if (ignore_using_decls) - continue; - 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)); - } - } - } - } - } - 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; - - // Currently DWARF has one shared translation unit for all Decls at top - // level, so this would erroneously find using statements anywhere. So - // don't look at the top-level translation unit. - // TODO fix this and add a testcase that depends on it. - - if (llvm::isa<clang::TranslationUnitDecl>(it->second)) - continue; - - searched.insert(it->second); - symbol_file->ParseDeclsForContext( - CreateDeclContext(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 = GetTypeForDecl(nd); - if (!AreTypesSame(clang_type, *child_type, - /*ignore_qualifiers=*/true)) - continue; - } - // Found it! - return level; - } - } - } - } - } - ++level; - } - } - return LLDB_INVALID_DECL_LEVEL; -} - -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(); -} - -ConstString -ClangASTContext::DeclContextGetScopeQualifiedName(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( - llvm::StringRef(named_decl->getQualifiedNameAsString())); - } - 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)) { - ClangASTMetadata *metadata = GetMetadata(function_decl); - if (metadata && metadata->HasObjectPtr()) { - 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 false; -} - -bool ClangASTContext::DeclContextIsContainedInLookup( - void *opaque_decl_ctx, void *other_opaque_decl_ctx) { - auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; - auto *other = (clang::DeclContext *)other_opaque_decl_ctx; - - do { - // A decl context always includes its own contents in its lookup. - if (decl_ctx == other) - return true; - - // If we have an inline namespace, then the lookup of the parent context - // also includes the inline namespace contents. - } while (other->isInlineNamespace() && (other = other->getParent())); - - return false; -} - -static bool IsClangDeclContext(const CompilerDeclContext &dc) { - return dc.IsValid() && isa<ClangASTContext>(dc.GetTypeSystem()); -} - -clang::DeclContext * -ClangASTContext::DeclContextGetAsDeclContext(const CompilerDeclContext &dc) { - if (IsClangDeclContext(dc)) - return (clang::DeclContext *)dc.GetOpaqueDeclContext(); - return nullptr; -} - -ObjCMethodDecl * -ClangASTContext::DeclContextGetAsObjCMethodDecl(const CompilerDeclContext &dc) { - if (IsClangDeclContext(dc)) - return llvm::dyn_cast<clang::ObjCMethodDecl>( - (clang::DeclContext *)dc.GetOpaqueDeclContext()); - return nullptr; -} - -CXXMethodDecl * -ClangASTContext::DeclContextGetAsCXXMethodDecl(const CompilerDeclContext &dc) { - if (IsClangDeclContext(dc)) - return llvm::dyn_cast<clang::CXXMethodDecl>( - (clang::DeclContext *)dc.GetOpaqueDeclContext()); - return nullptr; -} - -clang::FunctionDecl * -ClangASTContext::DeclContextGetAsFunctionDecl(const CompilerDeclContext &dc) { - if (IsClangDeclContext(dc)) - return llvm::dyn_cast<clang::FunctionDecl>( - (clang::DeclContext *)dc.GetOpaqueDeclContext()); - return nullptr; -} - -clang::NamespaceDecl * -ClangASTContext::DeclContextGetAsNamespaceDecl(const CompilerDeclContext &dc) { - if (IsClangDeclContext(dc)) - return llvm::dyn_cast<clang::NamespaceDecl>( - (clang::DeclContext *)dc.GetOpaqueDeclContext()); - return nullptr; -} - -ClangASTMetadata * -ClangASTContext::DeclContextGetMetaData(const CompilerDeclContext &dc, - const Decl *object) { - ClangASTContext *ast = llvm::cast<ClangASTContext>(dc.GetTypeSystem()); - return ast->GetMetadata(object); -} - -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, llvm::Triple triple) - : ClangASTContext(triple), m_target_wp(target.shared_from_this()), - m_persistent_variables(new ClangPersistentVariables) { - m_scratch_ast_source_up.reset(new ClangASTSource( - target.shared_from_this(), target.GetClangASTImporter())); - m_scratch_ast_source_up->InstallASTContext(*this); - llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source( - m_scratch_ast_source_up->CreateProxy()); - SetExternalSource(proxy_ast_source); -} - -void ClangASTContextForExpressions::Finalize() { - ClangASTContext::Finalize(); - m_scratch_ast_source_up.reset(); -} - -UserExpression *ClangASTContextForExpressions::GetUserExpression( - llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, - Expression::ResultType desired_type, - const EvaluateExpressionOptions &options, - ValueObject *ctx_obj) { - TargetSP target_sp = m_target_wp.lock(); - if (!target_sp) - return nullptr; - - return new ClangUserExpression(*target_sp.get(), expr, prefix, language, - desired_type, options, ctx_obj); -} - -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(); -} diff --git a/lldb/source/Symbol/ClangASTImporter.cpp b/lldb/source/Symbol/ClangASTImporter.cpp deleted file mode 100644 index 8cb404231a8d..000000000000 --- a/lldb/source/Symbol/ClangASTImporter.cpp +++ /dev/null @@ -1,1165 +0,0 @@ -//===-- ClangASTImporter.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Core/Module.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/Log.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Sema/Lookup.h" -#include "clang/Sema/Sema.h" -#include "llvm/Support/raw_ostream.h" - -#include <memory> - -using namespace lldb_private; -using namespace clang; - -CompilerType ClangASTImporter::CopyType(ClangASTContext &dst_ast, - const CompilerType &src_type) { - clang::ASTContext &dst_clang_ast = dst_ast.getASTContext(); - - ClangASTContext *src_ast = - llvm::dyn_cast_or_null<ClangASTContext>(src_type.GetTypeSystem()); - if (!src_ast) - return CompilerType(); - - clang::ASTContext &src_clang_ast = src_ast->getASTContext(); - - clang::QualType src_qual_type = ClangUtil::GetQualType(src_type); - - ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast)); - if (!delegate_sp) - return CompilerType(); - - ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast); - - llvm::Expected<QualType> ret_or_error = delegate_sp->Import(src_qual_type); - if (!ret_or_error) { - Log *log = - lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - LLDB_LOG_ERROR(log, ret_or_error.takeError(), - "Couldn't import type: {0}"); - return CompilerType(); - } - - lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr(); - - if (dst_clang_type) - return CompilerType(&dst_ast, dst_clang_type); - return CompilerType(); -} - -clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast, - clang::Decl *decl) { - ImporterDelegateSP delegate_sp; - - clang::ASTContext *src_ast = &decl->getASTContext(); - delegate_sp = GetDelegate(dst_ast, src_ast); - - ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast); - - if (!delegate_sp) - return nullptr; - - llvm::Expected<clang::Decl *> result = delegate_sp->Import(decl); - if (!result) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}"); - if (log) { - lldb::user_id_t user_id = LLDB_INVALID_UID; - ClangASTMetadata *metadata = GetDeclMetadata(decl); - if (metadata) - user_id = metadata->GetUserID(); - - if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl)) - LLDB_LOGF(log, - " [ClangASTImporter] WARNING: Failed to import a %s " - "'%s', metadata 0x%" PRIx64, - decl->getDeclKindName(), - named_decl->getNameAsString().c_str(), user_id); - else - LLDB_LOGF(log, - " [ClangASTImporter] WARNING: Failed to import a %s, " - "metadata 0x%" PRIx64, - decl->getDeclKindName(), user_id); - } - return nullptr; - } - - return *result; -} - -class DeclContextOverride { -private: - struct Backup { - clang::DeclContext *decl_context; - clang::DeclContext *lexical_decl_context; - }; - - llvm::DenseMap<clang::Decl *, Backup> m_backups; - - void OverrideOne(clang::Decl *decl) { - if (m_backups.find(decl) != m_backups.end()) { - return; - } - - m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()}; - - decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl()); - decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl()); - } - - bool ChainPassesThrough( - clang::Decl *decl, clang::DeclContext *base, - clang::DeclContext *(clang::Decl::*contextFromDecl)(), - clang::DeclContext *(clang::DeclContext::*contextFromContext)()) { - for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx; - decl_ctx = (decl_ctx->*contextFromContext)()) { - if (decl_ctx == base) { - return true; - } - } - - return false; - } - - clang::Decl *GetEscapedChild(clang::Decl *decl, - clang::DeclContext *base = nullptr) { - if (base) { - // decl's DeclContext chains must pass through base. - - if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext, - &clang::DeclContext::getParent) || - !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext, - &clang::DeclContext::getLexicalParent)) { - return decl; - } - } else { - base = clang::dyn_cast<clang::DeclContext>(decl); - - if (!base) { - return nullptr; - } - } - - if (clang::DeclContext *context = - clang::dyn_cast<clang::DeclContext>(decl)) { - for (clang::Decl *decl : context->decls()) { - if (clang::Decl *escaped_child = GetEscapedChild(decl)) { - return escaped_child; - } - } - } - - return nullptr; - } - - void Override(clang::Decl *decl) { - if (clang::Decl *escaped_child = GetEscapedChild(decl)) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - LLDB_LOGF(log, - " [ClangASTImporter] DeclContextOverride couldn't " - "override (%sDecl*)%p - its child (%sDecl*)%p escapes", - decl->getDeclKindName(), static_cast<void *>(decl), - escaped_child->getDeclKindName(), - static_cast<void *>(escaped_child)); - lldbassert(0 && "Couldn't override!"); - } - - OverrideOne(decl); - } - -public: - DeclContextOverride() {} - - void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) { - for (DeclContext *decl_context = decl->getLexicalDeclContext(); - decl_context; decl_context = decl_context->getLexicalParent()) { - DeclContext *redecl_context = decl_context->getRedeclContext(); - - if (llvm::isa<FunctionDecl>(redecl_context) && - llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) { - for (clang::Decl *child_decl : decl_context->decls()) { - Override(child_decl); - } - } - } - } - - ~DeclContextOverride() { - for (const std::pair<clang::Decl *, Backup> &backup : m_backups) { - backup.first->setDeclContext(backup.second.decl_context); - backup.first->setLexicalDeclContext(backup.second.lexical_decl_context); - } - } -}; - -namespace { -/// Completes all imported TagDecls at the end of the scope. -/// -/// While in a CompleteTagDeclsScope, every decl that could be completed will -/// be completed at the end of the scope (including all Decls that are -/// imported while completing the original Decls). -class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { - ClangASTImporter::ImporterDelegateSP m_delegate; - llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete; - llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed; - clang::ASTContext *m_dst_ctx; - clang::ASTContext *m_src_ctx; - ClangASTImporter &importer; - -public: - /// Constructs a CompleteTagDeclsScope. - /// \param importer The ClangASTImporter that we should observe. - /// \param dst_ctx The ASTContext to which Decls are imported. - /// \param src_ctx The ASTContext from which Decls are imported. - explicit CompleteTagDeclsScope(ClangASTImporter &importer, - clang::ASTContext *dst_ctx, - clang::ASTContext *src_ctx) - : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx), - m_src_ctx(src_ctx), importer(importer) { - m_delegate->SetImportListener(this); - } - - virtual ~CompleteTagDeclsScope() { - ClangASTImporter::ASTContextMetadataSP to_context_md = - importer.GetContextMetadata(m_dst_ctx); - - // Complete all decls we collected until now. - while (!m_decls_to_complete.empty()) { - NamedDecl *decl = m_decls_to_complete.pop_back_val(); - m_decls_already_completed.insert(decl); - - // We should only complete decls coming from the source context. - assert(to_context_md->m_origins[decl].ctx == m_src_ctx); - - Decl *original_decl = to_context_md->m_origins[decl].decl; - - // Complete the decl now. - ClangASTContext::GetCompleteDecl(m_src_ctx, original_decl); - if (auto *tag_decl = dyn_cast<TagDecl>(decl)) { - if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) { - if (original_tag_decl->isCompleteDefinition()) { - m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl); - tag_decl->setCompleteDefinition(true); - } - } - - tag_decl->setHasExternalLexicalStorage(false); - tag_decl->setHasExternalVisibleStorage(false); - } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) { - container_decl->setHasExternalLexicalStorage(false); - container_decl->setHasExternalVisibleStorage(false); - } - - to_context_md->m_origins.erase(decl); - } - - // Stop listening to imported decls. We do this after clearing the - // Decls we needed to import to catch all Decls they might have pulled in. - m_delegate->RemoveImportListener(); - } - - void NewDeclImported(clang::Decl *from, clang::Decl *to) override { - // Filter out decls that we can't complete later. - if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to)) - return; - RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from); - // We don't need to complete injected class name decls. - if (from_record_decl && from_record_decl->isInjectedClassName()) - return; - - NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to); - // Check if we already completed this type. - if (m_decls_already_completed.count(to_named_decl) != 0) - return; - m_decls_to_complete.push_back(to_named_decl); - } -}; -} // namespace - -CompilerType ClangASTImporter::DeportType(ClangASTContext &dst, - const CompilerType &src_type) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - ClangASTContext *src_ctxt = - llvm::cast<ClangASTContext>(src_type.GetTypeSystem()); - - LLDB_LOG(log, - " [ClangASTImporter] DeportType called on ({0}Type*){1:x} " - "from (ASTContext*){2:x} to (ASTContext*){3:x}", - src_type.GetTypeName(), src_type.GetOpaqueQualType(), - &src_ctxt->getASTContext(), &dst.getASTContext()); - - DeclContextOverride decl_context_override; - - if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>()) - decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl()); - - CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(), - &src_ctxt->getASTContext()); - return CopyType(dst, src_type); -} - -clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx, - clang::Decl *decl) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - clang::ASTContext *src_ctx = &decl->getASTContext(); - LLDB_LOGF(log, - " [ClangASTImporter] DeportDecl called on (%sDecl*)%p from " - "(ASTContext*)%p to (ASTContext*)%p", - decl->getDeclKindName(), static_cast<void *>(decl), - static_cast<void *>(src_ctx), static_cast<void *>(dst_ctx)); - - DeclContextOverride decl_context_override; - - decl_context_override.OverrideAllDeclsFromContainingFunction(decl); - - clang::Decl *result; - { - CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx); - result = CopyDecl(dst_ctx, decl); - } - - if (!result) - return nullptr; - - LLDB_LOGF( - log, - " [ClangASTImporter] DeportDecl deported (%sDecl*)%p to (%sDecl*)%p", - decl->getDeclKindName(), static_cast<void *>(decl), - result->getDeclKindName(), static_cast<void *>(result)); - - return result; -} - -bool ClangASTImporter::CanImport(const CompilerType &type) { - if (!ClangUtil::IsClangType(type)) - return false; - - // TODO: remove external completion BOOL - // CompleteAndFetchChildren should get the Decl out and check for the - - clang::QualType qual_type( - ClangUtil::GetCanonicalQualType(ClangUtil::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 (GetDeclOrigin(cxx_record_decl).Valid()) - return true; - } - } break; - - case clang::Type::Enum: { - clang::EnumDecl *enum_decl = - llvm::cast<clang::EnumType>(qual_type)->getDecl(); - if (enum_decl) { - if (GetDeclOrigin(enum_decl).Valid()) - 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 (GetDeclOrigin(class_interface_decl).Valid()) - return true; - } - } - } break; - - case clang::Type::Typedef: - return CanImport(CompilerType(type.GetTypeSystem(), - llvm::cast<clang::TypedefType>(qual_type) - ->getDecl() - ->getUnderlyingType() - .getAsOpaquePtr())); - - case clang::Type::Auto: - return CanImport(CompilerType(type.GetTypeSystem(), - llvm::cast<clang::AutoType>(qual_type) - ->getDeducedType() - .getAsOpaquePtr())); - - case clang::Type::Elaborated: - return CanImport(CompilerType(type.GetTypeSystem(), - llvm::cast<clang::ElaboratedType>(qual_type) - ->getNamedType() - .getAsOpaquePtr())); - - case clang::Type::Paren: - return CanImport(CompilerType( - type.GetTypeSystem(), - llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); - - default: - break; - } - - return false; -} - -bool ClangASTImporter::Import(const CompilerType &type) { - if (!ClangUtil::IsClangType(type)) - return false; - // TODO: remove external completion BOOL - // CompleteAndFetchChildren should get the Decl out and check for the - - clang::QualType qual_type( - ClangUtil::GetCanonicalQualType(ClangUtil::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 (GetDeclOrigin(cxx_record_decl).Valid()) - return CompleteAndFetchChildren(qual_type); - } - } break; - - case clang::Type::Enum: { - clang::EnumDecl *enum_decl = - llvm::cast<clang::EnumType>(qual_type)->getDecl(); - if (enum_decl) { - if (GetDeclOrigin(enum_decl).Valid()) - return 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 (GetDeclOrigin(class_interface_decl).Valid()) - return CompleteAndFetchChildren(qual_type); - } - } - } break; - - case clang::Type::Typedef: - return Import(CompilerType(type.GetTypeSystem(), - llvm::cast<clang::TypedefType>(qual_type) - ->getDecl() - ->getUnderlyingType() - .getAsOpaquePtr())); - - case clang::Type::Auto: - return Import(CompilerType(type.GetTypeSystem(), - llvm::cast<clang::AutoType>(qual_type) - ->getDeducedType() - .getAsOpaquePtr())); - - case clang::Type::Elaborated: - return Import(CompilerType(type.GetTypeSystem(), - llvm::cast<clang::ElaboratedType>(qual_type) - ->getNamedType() - .getAsOpaquePtr())); - - case clang::Type::Paren: - return Import(CompilerType( - type.GetTypeSystem(), - llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); - - default: - break; - } - return false; -} - -bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { - if (!CanImport(compiler_type)) - return false; - - if (Import(compiler_type)) { - ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); - return true; - } - - ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), - false); - return false; -} - -bool ClangASTImporter::LayoutRecordType( - 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) { - RecordDeclToLayoutMap::iterator pos = - m_record_decl_to_layout_map.find(record_decl); - bool success = false; - base_offsets.clear(); - vbase_offsets.clear(); - if (pos != m_record_decl_to_layout_map.end()) { - bit_size = pos->second.bit_size; - alignment = pos->second.alignment; - field_offsets.swap(pos->second.field_offsets); - base_offsets.swap(pos->second.base_offsets); - vbase_offsets.swap(pos->second.vbase_offsets); - m_record_decl_to_layout_map.erase(pos); - success = true; - } else { - bit_size = 0; - alignment = 0; - field_offsets.clear(); - } - return success; -} - -void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl, - const LayoutInfo &layout) { - m_record_decl_to_layout_map.insert(std::make_pair(decl, layout)); -} - -void ClangASTImporter::CompleteDecl(clang::Decl *decl) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - LLDB_LOGF(log, " [ClangASTImporter] CompleteDecl called on (%sDecl*)%p", - decl->getDeclKindName(), static_cast<void *>(decl)); - - if (ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl)) { - if (!interface_decl->getDefinition()) { - interface_decl->startDefinition(); - CompleteObjCInterfaceDecl(interface_decl); - } - } else if (ObjCProtocolDecl *protocol_decl = - dyn_cast<ObjCProtocolDecl>(decl)) { - if (!protocol_decl->getDefinition()) - protocol_decl->startDefinition(); - } else if (TagDecl *tag_decl = dyn_cast<TagDecl>(decl)) { - if (!tag_decl->getDefinition() && !tag_decl->isBeingDefined()) { - tag_decl->startDefinition(); - CompleteTagDecl(tag_decl); - tag_decl->setCompleteDefinition(true); - } - } else { - assert(0 && "CompleteDecl called on a Decl that can't be completed"); - } -} - -bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) { - DeclOrigin decl_origin = GetDeclOrigin(decl); - - if (!decl_origin.Valid()) - return false; - - if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) - return false; - - ImporterDelegateSP delegate_sp( - GetDelegate(&decl->getASTContext(), decl_origin.ctx)); - - ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, - &decl->getASTContext()); - if (delegate_sp) - delegate_sp->ImportDefinitionTo(decl, decl_origin.decl); - - return true; -} - -bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, - clang::TagDecl *origin_decl) { - clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext(); - - if (!ClangASTContext::GetCompleteDecl(origin_ast_ctx, origin_decl)) - return false; - - ImporterDelegateSP delegate_sp( - GetDelegate(&decl->getASTContext(), origin_ast_ctx)); - - if (delegate_sp) - delegate_sp->ImportDefinitionTo(decl, origin_decl); - - ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - OriginMap &origins = context_md->m_origins; - - origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl); - - return true; -} - -bool ClangASTImporter::CompleteObjCInterfaceDecl( - clang::ObjCInterfaceDecl *interface_decl) { - DeclOrigin decl_origin = GetDeclOrigin(interface_decl); - - if (!decl_origin.Valid()) - return false; - - if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) - return false; - - ImporterDelegateSP delegate_sp( - GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx)); - - if (delegate_sp) - delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl); - - if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass()) - RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0)); - - return true; -} - -bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) { - if (!RequireCompleteType(type)) - return false; - - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - - if (const TagType *tag_type = type->getAs<TagType>()) { - TagDecl *tag_decl = tag_type->getDecl(); - - DeclOrigin decl_origin = GetDeclOrigin(tag_decl); - - if (!decl_origin.Valid()) - return false; - - ImporterDelegateSP delegate_sp( - GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx)); - - ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, - &tag_decl->getASTContext()); - - TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl); - - for (Decl *origin_child_decl : origin_tag_decl->decls()) { - llvm::Expected<Decl *> imported_or_err = - delegate_sp->Import(origin_child_decl); - if (!imported_or_err) { - LLDB_LOG_ERROR(log, imported_or_err.takeError(), - "Couldn't import decl: {0}"); - return false; - } - } - - if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl)) - record_decl->setHasLoadedFieldsFromExternalStorage(true); - - return true; - } - - if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) { - if (ObjCInterfaceDecl *objc_interface_decl = - objc_object_type->getInterface()) { - DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl); - - if (!decl_origin.Valid()) - return false; - - ImporterDelegateSP delegate_sp( - GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx)); - - ObjCInterfaceDecl *origin_interface_decl = - llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl); - - for (Decl *origin_child_decl : origin_interface_decl->decls()) { - llvm::Expected<Decl *> imported_or_err = - delegate_sp->Import(origin_child_decl); - if (!imported_or_err) { - LLDB_LOG_ERROR(log, imported_or_err.takeError(), - "Couldn't import decl: {0}"); - return false; - } - } - - return true; - } - return false; - } - - return true; -} - -bool ClangASTImporter::RequireCompleteType(clang::QualType type) { - if (type.isNull()) - return false; - - if (const TagType *tag_type = type->getAs<TagType>()) { - TagDecl *tag_decl = tag_type->getDecl(); - - if (tag_decl->getDefinition() || tag_decl->isBeingDefined()) - return true; - - return CompleteTagDecl(tag_decl); - } - if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) { - if (ObjCInterfaceDecl *objc_interface_decl = - objc_object_type->getInterface()) - return CompleteObjCInterfaceDecl(objc_interface_decl); - return false; - } - if (const ArrayType *array_type = type->getAsArrayTypeUnsafe()) - return RequireCompleteType(array_type->getElementType()); - if (const AtomicType *atomic_type = type->getAs<AtomicType>()) - return RequireCompleteType(atomic_type->getPointeeType()); - - return true; -} - -ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) { - DeclOrigin decl_origin = GetDeclOrigin(decl); - - if (decl_origin.Valid()) { - ClangASTContext *ast = ClangASTContext::GetASTContext(decl_origin.ctx); - return ast->GetMetadata(decl_origin.decl); - } - ClangASTContext *ast = ClangASTContext::GetASTContext(&decl->getASTContext()); - return ast->GetMetadata(decl); -} - -ClangASTImporter::DeclOrigin -ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) { - ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) - return iter->second; - return DeclOrigin(); -} - -void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl, - clang::Decl *original_decl) { - ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) { - iter->second.decl = original_decl; - iter->second.ctx = &original_decl->getASTContext(); - return; - } - origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl); -} - -void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl, - NamespaceMapSP &namespace_map) { - ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - context_md->m_namespace_maps[decl] = namespace_map; -} - -ClangASTImporter::NamespaceMapSP -ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) { - ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps; - - NamespaceMetaMap::iterator iter = namespace_maps.find(decl); - - if (iter != namespace_maps.end()) - return iter->second; - return NamespaceMapSP(); -} - -void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) { - assert(decl); - ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - const DeclContext *parent_context = decl->getDeclContext(); - const NamespaceDecl *parent_namespace = - dyn_cast<NamespaceDecl>(parent_context); - NamespaceMapSP parent_map; - - if (parent_namespace) - parent_map = GetNamespaceMap(parent_namespace); - - NamespaceMapSP new_map; - - new_map = std::make_shared<NamespaceMap>(); - - if (context_md->m_map_completer) { - std::string namespace_string = decl->getDeclName().getAsString(); - - context_md->m_map_completer->CompleteNamespaceMap( - new_map, ConstString(namespace_string.c_str()), parent_map); - } - - context_md->m_namespace_maps[decl] = new_map; -} - -void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - LLDB_LOGF(log, - " [ClangASTImporter] Forgetting destination (ASTContext*)%p", - static_cast<void *>(dst_ast)); - - m_metadata_map.erase(dst_ast); -} - -void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, - clang::ASTContext *src_ast) { - ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast); - - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - LLDB_LOGF(log, - " [ClangASTImporter] Forgetting source->dest " - "(ASTContext*)%p->(ASTContext*)%p", - static_cast<void *>(src_ast), static_cast<void *>(dst_ast)); - - if (!md) - return; - - md->m_delegates.erase(src_ast); - - for (OriginMap::iterator iter = md->m_origins.begin(); - iter != md->m_origins.end();) { - if (iter->second.ctx == src_ast) - md->m_origins.erase(iter++); - else - ++iter; - } -} - -ClangASTImporter::MapCompleter::~MapCompleter() { return; } - -llvm::Expected<Decl *> -ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { - if (m_std_handler) { - llvm::Optional<Decl *> D = m_std_handler->Import(From); - if (D) { - // Make sure we don't use this decl later to map it back to it's original - // decl. The decl the CxxModuleHandler created has nothing to do with - // the one from debug info, and linking those two would just cause the - // ASTImporter to try 'updating' the module decl with the minimal one from - // the debug info. - m_decls_to_ignore.insert(*D); - return *D; - } - } - - // Check which ASTContext this declaration originally came from. - DeclOrigin origin = m_master.GetDeclOrigin(From); - // If it originally came from the target ASTContext then we can just - // pretend that the original is the one we imported. This can happen for - // example when inspecting a persistent declaration from the scratch - // ASTContext (which will provide the declaration when parsing the - // expression and then we later try to copy the declaration back to the - // scratch ASTContext to store the result). - // Without this check we would ask the ASTImporter to import a declaration - // into the same ASTContext where it came from (which doesn't make a lot of - // sense). - if (origin.Valid() && origin.ctx == &getToContext()) { - RegisterImportedDecl(From, origin.decl); - return origin.decl; - } - - // This declaration came originally from another ASTContext. Instead of - // copying our potentially incomplete 'From' Decl we instead go to the - // original ASTContext and copy the original to the target. This is not - // only faster than first completing our current decl and then copying it - // to the target, but it also prevents that indirectly copying the same - // declaration to the same target requires the ASTImporter to merge all - // the different decls that appear to come from different ASTContexts (even - // though all these different source ASTContexts just got a copy from - // one source AST). - if (origin.Valid()) { - auto R = m_master.CopyDecl(&getToContext(), origin.decl); - if (R) { - RegisterImportedDecl(From, R); - return R; - } - } - - return ASTImporter::ImportImpl(From); -} - -void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( - clang::Decl *to, clang::Decl *from) { - ASTImporter::Imported(from, to); - - /* - if (to_objc_interface) - to_objc_interface->startDefinition(); - - CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to); - - if (to_cxx_record) - to_cxx_record->startDefinition(); - */ - - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - - if (llvm::Error err = ImportDefinition(from)) { - LLDB_LOG_ERROR(log, std::move(err), - "[ClangASTImporter] Error during importing definition: {0}"); - return; - } - - if (clang::TagDecl *to_tag = dyn_cast<clang::TagDecl>(to)) { - if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(from)) { - to_tag->setCompleteDefinition(from_tag->isCompleteDefinition()); - - if (Log *log_ast = - lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST)) { - std::string name_string; - if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) { - llvm::raw_string_ostream name_stream(name_string); - from_named_decl->printName(name_stream); - name_stream.flush(); - } - LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0}] Imported " - "({1}Decl*){2}, named {3} (from " - "(Decl*){4})", - static_cast<void *>(to->getTranslationUnitDecl()), - from->getDeclKindName(), static_cast<void *>(to), name_string, - static_cast<void *>(from)); - - // Log the AST of the TU. - std::string ast_string; - llvm::raw_string_ostream ast_stream(ast_string); - to->getTranslationUnitDecl()->dump(ast_stream); - LLDB_LOG(log_ast, "{0}", ast_string); - } - } - } - - // If we're dealing with an Objective-C class, ensure that the inheritance - // has been set up correctly. The ASTImporter may not do this correctly if - // the class was originally sourced from symbols. - - if (ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to)) { - do { - ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass(); - - if (to_superclass) - break; // we're not going to override it if it's set - - ObjCInterfaceDecl *from_objc_interface = - dyn_cast<ObjCInterfaceDecl>(from); - - if (!from_objc_interface) - break; - - ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass(); - - if (!from_superclass) - break; - - llvm::Expected<Decl *> imported_from_superclass_decl = - Import(from_superclass); - - if (!imported_from_superclass_decl) { - LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(), - "Couldn't import decl: {0}"); - break; - } - - ObjCInterfaceDecl *imported_from_superclass = - dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl); - - if (!imported_from_superclass) - break; - - if (!to_objc_interface->hasDefinition()) - to_objc_interface->startDefinition(); - - to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo( - m_source_ctx->getObjCInterfaceType(imported_from_superclass))); - } while (false); - } -} - -void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, - clang::Decl *to) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - // Some decls shouldn't be tracked here because they were not created by - // copying 'from' to 'to'. Just exit early for those. - if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end()) - return clang::ASTImporter::Imported(from, to); - - lldb::user_id_t user_id = LLDB_INVALID_UID; - ClangASTMetadata *metadata = m_master.GetDeclMetadata(from); - if (metadata) - user_id = metadata->GetUserID(); - - if (log) { - if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) { - std::string name_string; - llvm::raw_string_ostream name_stream(name_string); - from_named_decl->printName(name_stream); - name_stream.flush(); - - LLDB_LOGF(log, - " [ClangASTImporter] Imported (%sDecl*)%p, named %s (from " - "(Decl*)%p), metadata 0x%" PRIx64, - from->getDeclKindName(), static_cast<void *>(to), - name_string.c_str(), static_cast<void *>(from), user_id); - } else { - LLDB_LOGF(log, - " [ClangASTImporter] Imported (%sDecl*)%p (from " - "(Decl*)%p), metadata 0x%" PRIx64, - from->getDeclKindName(), static_cast<void *>(to), - static_cast<void *>(from), user_id); - } - } - - ASTContextMetadataSP to_context_md = - m_master.GetContextMetadata(&to->getASTContext()); - ASTContextMetadataSP from_context_md = - m_master.MaybeGetContextMetadata(m_source_ctx); - - if (from_context_md) { - OriginMap &origins = from_context_md->m_origins; - - OriginMap::iterator origin_iter = origins.find(from); - - if (origin_iter != origins.end()) { - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - if (origin_iter->second.ctx != &to->getASTContext()) - to_context_md->m_origins[to] = origin_iter->second; - } - - ImporterDelegateSP direct_completer = - m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx); - - if (direct_completer.get() != this) - direct_completer->ASTImporter::Imported(origin_iter->second.decl, to); - - LLDB_LOGF(log, - " [ClangASTImporter] Propagated origin " - "(Decl*)%p/(ASTContext*)%p from (ASTContext*)%p to " - "(ASTContext*)%p", - static_cast<void *>(origin_iter->second.decl), - static_cast<void *>(origin_iter->second.ctx), - static_cast<void *>(&from->getASTContext()), - static_cast<void *>(&to->getASTContext())); - } else { - if (m_new_decl_listener) - m_new_decl_listener->NewDeclImported(from, to); - - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); - } - - LLDB_LOGF(log, - " [ClangASTImporter] Decl has no origin information in " - "(ASTContext*)%p", - static_cast<void *>(&from->getASTContext())); - } - - if (clang::NamespaceDecl *to_namespace = - dyn_cast<clang::NamespaceDecl>(to)) { - clang::NamespaceDecl *from_namespace = - dyn_cast<clang::NamespaceDecl>(from); - - NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps; - - NamespaceMetaMap::iterator namespace_map_iter = - namespace_maps.find(from_namespace); - - if (namespace_map_iter != namespace_maps.end()) - to_context_md->m_namespace_maps[to_namespace] = - namespace_map_iter->second; - } - } else { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); - - LLDB_LOGF(log, - " [ClangASTImporter] Sourced origin " - "(Decl*)%p/(ASTContext*)%p into (ASTContext*)%p", - static_cast<void *>(from), static_cast<void *>(m_source_ctx), - static_cast<void *>(&to->getASTContext())); - } - - if (TagDecl *from_tag_decl = dyn_cast<TagDecl>(from)) { - TagDecl *to_tag_decl = dyn_cast<TagDecl>(to); - - to_tag_decl->setHasExternalLexicalStorage(); - to_tag_decl->getPrimaryContext()->setMustBuildLookupTable(); - - LLDB_LOGF( - log, - " [ClangASTImporter] To is a TagDecl - attributes %s%s [%s->%s]", - (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""), - (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""), - (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"), - (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete")); - } - - if (isa<NamespaceDecl>(from)) { - NamespaceDecl *to_namespace_decl = dyn_cast<NamespaceDecl>(to); - - m_master.BuildNamespaceMap(to_namespace_decl); - - to_namespace_decl->setHasExternalVisibleStorage(); - } - - if (isa<ObjCContainerDecl>(from)) { - ObjCContainerDecl *to_container_decl = dyn_cast<ObjCContainerDecl>(to); - - to_container_decl->setHasExternalLexicalStorage(); - to_container_decl->setHasExternalVisibleStorage(); - - /*to_interface_decl->setExternallyCompleted();*/ - - if (log) { - if (ObjCInterfaceDecl *to_interface_decl = - llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) { - LLDB_LOGF( - log, - " [ClangASTImporter] To is an ObjCInterfaceDecl - attributes " - "%s%s%s", - (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""), - (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""), - (to_interface_decl->hasDefinition() ? " HasDefinition" : "")); - } else { - LLDB_LOGF( - log, " [ClangASTImporter] To is an %sDecl - attributes %s%s", - ((Decl *)to_container_decl)->getDeclKindName(), - (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""), - (to_container_decl->hasExternalVisibleStorage() ? " Visible" : "")); - } - } - } -} - -clang::Decl * -ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) { - return m_master.GetDeclOrigin(To).decl; -} diff --git a/lldb/source/Symbol/ClangASTMetadata.cpp b/lldb/source/Symbol/ClangASTMetadata.cpp deleted file mode 100644 index 31b012f553fa..000000000000 --- a/lldb/source/Symbol/ClangASTMetadata.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//===-- ClangASTMetadata.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Utility/Stream.h" - -using namespace lldb_private; - -void ClangASTMetadata::Dump(Stream *s) { - lldb::user_id_t uid = GetUserID(); - - if (uid != LLDB_INVALID_UID) { - s->Printf("uid=0x%" PRIx64, uid); - } - - uint64_t isa_ptr = GetISAPtr(); - if (isa_ptr != 0) { - s->Printf("isa_ptr=0x%" PRIx64, isa_ptr); - } - - const char *obj_ptr_name = GetObjectPtrName(); - if (obj_ptr_name) { - s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name); - } - - if (m_is_dynamic_cxx) { - s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx); - } - s->EOL(); -} diff --git a/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp deleted file mode 100644 index 008c2acd9b48..000000000000 --- a/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===-- ClangExternalASTSourceCallbacks.cpp ---------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" -#include "lldb/Symbol/ClangASTContext.h" - -#include "clang/AST/Decl.h" - -using namespace lldb_private; - -void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) { - m_ast.CompleteTagDecl(tag_decl); -} - -void ClangExternalASTSourceCallbacks::CompleteType( - clang::ObjCInterfaceDecl *objc_decl) { - m_ast.CompleteObjCInterfaceDecl(objc_decl); -} - -bool ClangExternalASTSourceCallbacks::layoutRecordType( - const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, - llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> - &VirtualBaseOffsets) { - return m_ast.LayoutRecordType(Record, Size, Alignment, FieldOffsets, - BaseOffsets, VirtualBaseOffsets); -} - -void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls( - const clang::DeclContext *decl_ctx, - llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, - llvm::SmallVectorImpl<clang::Decl *> &decls) { - if (decl_ctx) { - clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>( - const_cast<clang::DeclContext *>(decl_ctx)); - if (tag_decl) - CompleteType(tag_decl); - } -} diff --git a/lldb/source/Symbol/ClangUtil.cpp b/lldb/source/Symbol/ClangUtil.cpp deleted file mode 100644 index 52ea4f5111d6..000000000000 --- a/lldb/source/Symbol/ClangUtil.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//===-- ClangUtil.cpp -------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// A collection of helper methods and data structures for manipulating clang -// types and decls. -//===----------------------------------------------------------------------===// - -#include "lldb/Symbol/ClangUtil.h" -#include "lldb/Symbol/ClangASTContext.h" - -using namespace clang; -using namespace lldb_private; - -bool ClangUtil::IsClangType(const CompilerType &ct) { - // Invalid types are never Clang types. - if (!ct) - return false; - - if (llvm::dyn_cast_or_null<ClangASTContext>(ct.GetTypeSystem()) == nullptr) - return false; - - if (!ct.GetOpaqueQualType()) - return false; - - return true; -} - -QualType ClangUtil::GetQualType(const CompilerType &ct) { - // Make sure we have a clang type before making a clang::QualType - if (!IsClangType(ct)) - return QualType(); - - return QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); -} - -QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) { - if (!IsClangType(ct)) - return QualType(); - - return GetQualType(ct).getCanonicalType(); -} - -CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) { - if (!IsClangType(ct)) - return ct; - - QualType qual_type(GetQualType(ct)); - qual_type.removeLocalFastQualifiers(); - return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr()); -} - -clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) { - clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type); - if (qual_type.isNull()) - return nullptr; - - return qual_type->getAsTagDecl(); -} - -std::string ClangUtil::DumpDecl(const clang::Decl *d) { - if (!d) - return "nullptr"; - - std::string result; - llvm::raw_string_ostream stream(result); - bool deserialize = false; - d->dump(stream, deserialize); - - stream.flush(); - return result; -} - -std::string ClangUtil::ToString(const clang::Type *t) { - return clang::QualType(t, 0).getAsString(); -} - -std::string ClangUtil::ToString(const CompilerType &c) { - return ClangUtil::GetQualType(c).getAsString(); -} diff --git a/lldb/source/Symbol/CompactUnwindInfo.cpp b/lldb/source/Symbol/CompactUnwindInfo.cpp index 3eee7f785f36..1bb7cd1fc05b 100644 --- a/lldb/source/Symbol/CompactUnwindInfo.cpp +++ b/lldb/source/Symbol/CompactUnwindInfo.cpp @@ -1,4 +1,4 @@ -//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===// +//===-- CompactUnwindInfo.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp index b05036e27fcf..0c67bf5b702a 100644 --- a/lldb/source/Symbol/CompileUnit.cpp +++ b/lldb/source/Symbol/CompileUnit.cpp @@ -1,4 +1,4 @@ -//===-- CompileUnit.cpp -----------------------------------------*- C++ -*-===// +//===-- CompileUnit.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/CompilerDecl.cpp b/lldb/source/Symbol/CompilerDecl.cpp index 48d9169c1a7a..3cafa9535a72 100644 --- a/lldb/source/Symbol/CompilerDecl.cpp +++ b/lldb/source/Symbol/CompilerDecl.cpp @@ -1,4 +1,4 @@ -//===-- CompilerDecl.cpp ----------------------------------------*- C++ -*-===// +//===-- CompilerDecl.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/CompilerDeclContext.cpp b/lldb/source/Symbol/CompilerDeclContext.cpp index 581e0872a6a7..a3af568e7c99 100644 --- a/lldb/source/Symbol/CompilerDeclContext.cpp +++ b/lldb/source/Symbol/CompilerDeclContext.cpp @@ -1,4 +1,4 @@ -//===-- CompilerDeclContext.cpp ---------------------------------*- C++ -*-===// +//===-- CompilerDeclContext.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 09930f7a800e..f819c9f8ce23 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -1,4 +1,4 @@ -//===-- CompilerType.cpp ----------------------------------------*- C++ -*-===// +//===-- CompilerType.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -268,19 +268,6 @@ size_t CompilerType::GetPointerByteSize() const { return 0; } -ConstString CompilerType::GetConstQualifiedTypeName() const { - return GetConstTypeName(); -} - -ConstString CompilerType::GetConstTypeName() const { - if (IsValid()) { - ConstString type_name(GetTypeName()); - if (type_name) - return type_name; - } - return ConstString("<invalid>"); -} - ConstString CompilerType::GetTypeName() const { if (IsValid()) { return m_type_system->GetTypeName(m_type); @@ -288,7 +275,11 @@ ConstString CompilerType::GetTypeName() const { return ConstString("<invalid>"); } -ConstString CompilerType::GetDisplayTypeName() const { return GetTypeName(); } +ConstString CompilerType::GetDisplayTypeName() const { + if (IsValid()) + return m_type_system->GetDisplayTypeName(m_type); + return ConstString("<invalid>"); +} uint32_t CompilerType::GetTypeInfo( CompilerType *pointee_or_element_compiler_type) const { @@ -448,11 +439,11 @@ CompilerType CompilerType::AddRestrictModifier() const { return CompilerType(); } -CompilerType -CompilerType::CreateTypedef(const char *name, - const CompilerDeclContext &decl_ctx) const { +CompilerType CompilerType::CreateTypedef(const char *name, + const CompilerDeclContext &decl_ctx, + uint32_t payload) const { if (IsValid()) - return m_type_system->CreateTypedef(m_type, name, decl_ctx); + return m_type_system->CreateTypedef(m_type, name, decl_ctx, payload); else return CompilerType(); } @@ -715,7 +706,6 @@ CompilerType::GetIndexOfChildWithName(const char *name, } // Dumping types -#define DEPTH_INCREMENT 2 void CompilerType::DumpValue(ExecutionContext *exe_ctx, Stream *s, lldb::Format format, const DataExtractor &data, @@ -753,14 +743,15 @@ void CompilerType::DumpSummary(ExecutionContext *exe_ctx, Stream *s, data_byte_size); } -void CompilerType::DumpTypeDescription() const { +void CompilerType::DumpTypeDescription(lldb::DescriptionLevel level) const { if (IsValid()) - m_type_system->DumpTypeDescription(m_type); + m_type_system->DumpTypeDescription(m_type, level); } -void CompilerType::DumpTypeDescription(Stream *s) const { +void CompilerType::DumpTypeDescription(Stream *s, + lldb::DescriptionLevel level) const { if (IsValid()) { - m_type_system->DumpTypeDescription(m_type, s); + m_type_system->DumpTypeDescription(m_type, s, level); } } @@ -874,6 +865,12 @@ bool CompilerType::GetValueAsScalar(const lldb_private::DataExtractor &data, return false; } +#ifndef NDEBUG +bool CompilerType::Verify() const { + return !IsValid() || m_type_system->Verify(m_type); +} +#endif + bool lldb_private::operator==(const lldb_private::CompilerType &lhs, const lldb_private::CompilerType &rhs) { return lhs.GetTypeSystem() == rhs.GetTypeSystem() && diff --git a/lldb/source/Symbol/CxxModuleHandler.cpp b/lldb/source/Symbol/CxxModuleHandler.cpp deleted file mode 100644 index 19e80e5036bc..000000000000 --- a/lldb/source/Symbol/CxxModuleHandler.cpp +++ /dev/null @@ -1,289 +0,0 @@ -//===-- CxxModuleHandler.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Symbol/CxxModuleHandler.h" - -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Utility/Log.h" -#include "clang/Sema/Lookup.h" -#include "llvm/Support/Error.h" - -using namespace lldb_private; -using namespace clang; - -CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) - : m_importer(&importer), - m_sema(ClangASTContext::GetASTContext(target)->getSema()) { - - std::initializer_list<const char *> supported_names = { - // containers - "deque", - "forward_list", - "list", - "queue", - "stack", - "vector", - // pointers - "shared_ptr", - "unique_ptr", - "weak_ptr", - // utility - "allocator", - }; - m_supported_templates.insert(supported_names.begin(), supported_names.end()); -} - -/// Builds a list of scopes that point into the given context. -/// -/// \param sema The sema that will be using the scopes. -/// \param ctxt The context that the scope should look into. -/// \param result A list of scopes. The scopes need to be freed by the caller -/// (except the TUScope which is owned by the sema). -static void makeScopes(Sema &sema, DeclContext *ctxt, - std::vector<Scope *> &result) { - // FIXME: The result should be a list of unique_ptrs, but the TUScope makes - // this currently impossible as it's owned by the Sema. - - if (auto parent = ctxt->getParent()) { - makeScopes(sema, parent, result); - - Scope *scope = - new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics()); - scope->setEntity(ctxt); - result.push_back(scope); - } else - result.push_back(sema.TUScope); -} - -/// Uses the Sema to look up the given name in the given DeclContext. -static std::unique_ptr<LookupResult> -emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) { - IdentifierInfo &ident = sema.getASTContext().Idents.get(name); - - std::unique_ptr<LookupResult> lookup_result; - lookup_result.reset(new LookupResult(sema, DeclarationName(&ident), - SourceLocation(), - Sema::LookupOrdinaryName)); - - // Usually during parsing we already encountered the scopes we would use. But - // here don't have these scopes so we have to emulate the behavior of the - // Sema during parsing. - std::vector<Scope *> scopes; - makeScopes(sema, ctxt, scopes); - - // Now actually perform the lookup with the sema. - sema.LookupName(*lookup_result, scopes.back()); - - // Delete all the allocated scopes beside the translation unit scope (which - // has depth 0). - for (Scope *s : scopes) - if (s->getDepth() != 0) - delete s; - - return lookup_result; -} - -/// Error class for handling problems when finding a certain DeclContext. -struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> { - - static char ID; - - MissingDeclContext(DeclContext *context, std::string error) - : m_context(context), m_error(error) {} - - DeclContext *m_context; - std::string m_error; - - void log(llvm::raw_ostream &OS) const override { - OS << llvm::formatv("error when reconstructing context of kind {0}:{1}", - m_context->getDeclKindName(), m_error); - } - - std::error_code convertToErrorCode() const override { - return llvm::inconvertibleErrorCode(); - } -}; - -char MissingDeclContext::ID = 0; - -/// Given a foreign decl context, this function finds the equivalent local -/// decl context in the ASTContext of the given Sema. Potentially deserializes -/// decls from the 'std' module if necessary. -static llvm::Expected<DeclContext *> -getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) { - - // Inline namespaces don't matter for lookups, so let's skip them. - while (foreign_ctxt && foreign_ctxt->isInlineNamespace()) - foreign_ctxt = foreign_ctxt->getParent(); - - // If the foreign context is the TU, we just return the local TU. - if (foreign_ctxt->isTranslationUnit()) - return sema.getASTContext().getTranslationUnitDecl(); - - // Recursively find/build the parent DeclContext. - llvm::Expected<DeclContext *> parent = - getEqualLocalDeclContext(sema, foreign_ctxt->getParent()); - if (!parent) - return parent; - - // We currently only support building namespaces. - if (foreign_ctxt->isNamespace()) { - NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt); - llvm::StringRef ns_name = ns->getName(); - - auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent); - for (NamedDecl *named_decl : *lookup_result) { - if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl)) - return DC->getPrimaryContext(); - } - return llvm::make_error<MissingDeclContext>( - foreign_ctxt, - "Couldn't find namespace " + ns->getQualifiedNameAsString()); - } - - return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context "); -} - -/// Returns true iff tryInstantiateStdTemplate supports instantiating a template -/// with the given template arguments. -static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) { - for (const TemplateArgument &arg : a) { - switch (arg.getKind()) { - case TemplateArgument::Type: - case TemplateArgument::Integral: - break; - default: - // TemplateArgument kind hasn't been handled yet. - return false; - } - } - return true; -} - -/// Constructor function for Clang declarations. Ensures that the created -/// declaration is registered with the ASTImporter. -template <typename T, typename... Args> -T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) { - T *to_d = T::Create(std::forward<Args>(args)...); - importer.RegisterImportedDecl(from_d, to_d); - return to_d; -} - -llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - - // If we don't have a template to instiantiate, then there is nothing to do. - auto td = dyn_cast<ClassTemplateSpecializationDecl>(d); - if (!td) - return {}; - - // We only care about templates in the std namespace. - if (!td->getDeclContext()->isStdNamespace()) - return {}; - - // We have a whitelist of supported template names. - if (m_supported_templates.find(td->getName()) == m_supported_templates.end()) - return {}; - - // Early check if we even support instantiating this template. We do this - // before we import anything into the target AST. - auto &foreign_args = td->getTemplateInstantiationArgs(); - if (!templateArgsAreSupported(foreign_args.asArray())) - return {}; - - // Find the local DeclContext that corresponds to the DeclContext of our - // decl we want to import. - llvm::Expected<DeclContext *> to_context = - getEqualLocalDeclContext(*m_sema, td->getDeclContext()); - if (!to_context) { - LLDB_LOG_ERROR(log, to_context.takeError(), - "Got error while searching equal local DeclContext for decl " - "'{1}':\n{0}", - td->getName()); - return {}; - } - - // Look up the template in our local context. - std::unique_ptr<LookupResult> lookup = - emulateLookupInCtxt(*m_sema, td->getName(), *to_context); - - ClassTemplateDecl *new_class_template = nullptr; - for (auto LD : *lookup) { - if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD))) - break; - } - if (!new_class_template) - return {}; - - // Import the foreign template arguments. - llvm::SmallVector<TemplateArgument, 4> imported_args; - - // If this logic is changed, also update templateArgsAreSupported. - for (const TemplateArgument &arg : foreign_args.asArray()) { - switch (arg.getKind()) { - case TemplateArgument::Type: { - llvm::Expected<QualType> type = m_importer->Import(arg.getAsType()); - if (!type) { - LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; - } - imported_args.push_back(TemplateArgument(*type)); - break; - } - case TemplateArgument::Integral: { - llvm::APSInt integral = arg.getAsIntegral(); - llvm::Expected<QualType> type = - m_importer->Import(arg.getIntegralType()); - if (!type) { - LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; - } - imported_args.push_back( - TemplateArgument(d->getASTContext(), integral, *type)); - break; - } - default: - assert(false && "templateArgsAreSupported not updated?"); - } - } - - // Find the class template specialization declaration that - // corresponds to these arguments. - void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *result = - new_class_template->findSpecialization(imported_args, InsertPos); - - if (result) { - // We found an existing specialization in the module that fits our arguments - // so we can treat it as the result and register it with the ASTImporter. - m_importer->RegisterImportedDecl(d, result); - return result; - } - - // Instantiate the template. - result = createDecl<ClassTemplateSpecializationDecl>( - *m_importer, d, m_sema->getASTContext(), - new_class_template->getTemplatedDecl()->getTagKind(), - new_class_template->getDeclContext(), - new_class_template->getTemplatedDecl()->getLocation(), - new_class_template->getLocation(), new_class_template, imported_args, - nullptr); - - new_class_template->AddSpecialization(result, InsertPos); - if (new_class_template->isOutOfLine()) - result->setLexicalDeclContext( - new_class_template->getLexicalDeclContext()); - return result; -} - -llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) { - if (!isValid()) - return {}; - - return tryInstantiateStdTemplate(d); -} diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index b4e74e9a2898..3111c33c7108 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -1,4 +1,4 @@ -//===-- DWARFCallFrameInfo.cpp ----------------------------------*- C++ -*-===// +//===-- DWARFCallFrameInfo.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -690,7 +690,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *row.get(); row.reset(newrow); - row->SetOffset(m_cfi_data.GetPointer(&offset) - + row->SetOffset(m_cfi_data.GetAddress(&offset) - startaddr.GetFileAddress()); break; } diff --git a/lldb/source/Symbol/DebugMacros.cpp b/lldb/source/Symbol/DebugMacros.cpp index d119a78868a4..d6a4ca96a30a 100644 --- a/lldb/source/Symbol/DebugMacros.cpp +++ b/lldb/source/Symbol/DebugMacros.cpp @@ -1,4 +1,4 @@ -//===-- DebugMacros.cpp -----------------------------------------*- C++ -*-===// +//===-- DebugMacros.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/DeclVendor.cpp b/lldb/source/Symbol/DeclVendor.cpp index 9ccf422e3bea..cf87f4f879b1 100644 --- a/lldb/source/Symbol/DeclVendor.cpp +++ b/lldb/source/Symbol/DeclVendor.cpp @@ -1,4 +1,4 @@ -//===-- DeclVendor.cpp ------------------------------------------*- C++ -*-===// +//===-- DeclVendor.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/Declaration.cpp b/lldb/source/Symbol/Declaration.cpp index 4d0975d34256..48d8013811d9 100644 --- a/lldb/source/Symbol/Declaration.cpp +++ b/lldb/source/Symbol/Declaration.cpp @@ -1,4 +1,4 @@ -//===-- Declaration.cpp -----------------------------------------*- C++ -*-===// +//===-- Declaration.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp index 7a6f3cefea66..30266120d05e 100644 --- a/lldb/source/Symbol/FuncUnwinders.cpp +++ b/lldb/source/Symbol/FuncUnwinders.cpp @@ -1,4 +1,4 @@ -//===-- FuncUnwinders.cpp ----------------------------------*- C++ -*-===// +//===-- FuncUnwinders.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index e92585ccfed7..67013f6dd8b1 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -1,4 +1,4 @@ -//===-- Function.cpp --------------------------------------------*- C++ -*-===// +//===-- Function.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -82,25 +82,24 @@ void InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const { m_mangled.Dump(s); } -void InlineFunctionInfo::DumpStopContext(Stream *s, - LanguageType language) const { +void InlineFunctionInfo::DumpStopContext(Stream *s) const { // s->Indent("[inlined] "); s->Indent(); if (m_mangled) - s->PutCString(m_mangled.GetName(language).AsCString()); + s->PutCString(m_mangled.GetName().AsCString()); else s->PutCString(m_name.AsCString()); } -ConstString InlineFunctionInfo::GetName(LanguageType language) const { +ConstString InlineFunctionInfo::GetName() const { if (m_mangled) - return m_mangled.GetName(language); + return m_mangled.GetName(); return m_name; } -ConstString InlineFunctionInfo::GetDisplayName(LanguageType language) const { +ConstString InlineFunctionInfo::GetDisplayName() const { if (m_mangled) - return m_mangled.GetDisplayDemangledName(language); + return m_mangled.GetDisplayDemangledName(); return m_name; } @@ -121,10 +120,32 @@ size_t InlineFunctionInfo::MemorySize() const { /// @name Call site related structures /// @{ +lldb::addr_t CallEdge::GetLoadAddress(lldb::addr_t unresolved_pc, + Function &caller, Target &target) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + const Address &caller_start_addr = caller.GetAddressRange().GetBaseAddress(); + + ModuleSP caller_module_sp = caller_start_addr.GetModule(); + if (!caller_module_sp) { + LLDB_LOG(log, "GetLoadAddress: cannot get Module for caller"); + return LLDB_INVALID_ADDRESS; + } + + SectionList *section_list = caller_module_sp->GetSectionList(); + if (!section_list) { + LLDB_LOG(log, "GetLoadAddress: cannot get SectionList for Module"); + return LLDB_INVALID_ADDRESS; + } + + Address the_addr = Address(unresolved_pc, section_list); + lldb::addr_t load_addr = the_addr.GetLoadAddress(&target); + return load_addr; +} + lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, Target &target) const { - const Address &base = caller.GetAddressRange().GetBaseAddress(); - return base.GetLoadAddress(&target) + return_pc; + return GetLoadAddress(GetUnresolvedReturnPCAddress(), caller, target); } void DirectCallEdge::ParseSymbolFileAndResolve(ModuleList &images) { @@ -269,6 +290,8 @@ void Function::GetEndLineSourceInfo(FileSpec &source_file, uint32_t &line_no) { } llvm::ArrayRef<std::unique_ptr<CallEdge>> Function::GetCallEdges() { + std::lock_guard<std::mutex> guard(m_call_edges_lock); + if (m_call_edges_resolved) return m_call_edges; @@ -288,36 +311,34 @@ llvm::ArrayRef<std::unique_ptr<CallEdge>> Function::GetCallEdges() { m_call_edges = sym_file->ParseCallEdgesInFunction(GetID()); // Sort the call edges to speed up return_pc lookups. - llvm::sort(m_call_edges.begin(), m_call_edges.end(), - [](const std::unique_ptr<CallEdge> &LHS, - const std::unique_ptr<CallEdge> &RHS) { - return LHS->GetUnresolvedReturnPCAddress() < - RHS->GetUnresolvedReturnPCAddress(); - }); + llvm::sort(m_call_edges, [](const std::unique_ptr<CallEdge> &LHS, + const std::unique_ptr<CallEdge> &RHS) { + return LHS->GetSortKey() < RHS->GetSortKey(); + }); return m_call_edges; } llvm::ArrayRef<std::unique_ptr<CallEdge>> Function::GetTailCallingEdges() { - // Call edges are sorted by return PC, and tail calling edges have invalid - // return PCs. Find them at the end of the list. - return GetCallEdges().drop_until([](const std::unique_ptr<CallEdge> &edge) { - return edge->GetUnresolvedReturnPCAddress() == LLDB_INVALID_ADDRESS; - }); + // Tail calling edges are sorted at the end of the list. Find them by dropping + // all non-tail-calls. + return GetCallEdges().drop_until( + [](const std::unique_ptr<CallEdge> &edge) { return edge->IsTailCall(); }); } CallEdge *Function::GetCallEdgeForReturnAddress(addr_t return_pc, Target &target) { auto edges = GetCallEdges(); auto edge_it = - std::lower_bound(edges.begin(), edges.end(), return_pc, - [&](const std::unique_ptr<CallEdge> &edge, addr_t pc) { - return edge->GetReturnPCAddress(*this, target) < pc; - }); + llvm::partition_point(edges, [&](const std::unique_ptr<CallEdge> &edge) { + return std::make_pair(edge->IsTailCall(), + edge->GetReturnPCAddress(*this, target)) < + std::make_pair(false, return_pc); + }); if (edge_it == edges.end() || edge_it->get()->GetReturnPCAddress(*this, target) != return_pc) return nullptr; - return &const_cast<CallEdge &>(*edge_it->get()); + return edge_it->get(); } Block &Function::GetBlock(bool can_create) { @@ -349,9 +370,9 @@ void Function::GetDescription(Stream *s, lldb::DescriptionLevel level, *s << "id = " << (const UserID &)*this; if (name) - *s << ", name = \"" << name.GetCString() << '"'; + s->AsRawOstream() << ", name = \"" << name << '"'; if (mangled) - *s << ", mangled = \"" << mangled.GetCString() << '"'; + s->AsRawOstream() << ", mangled = \"" << mangled << '"'; *s << ", range = "; Address::DumpStyle fallback_style; if (level == eDescriptionLevelVerbose) @@ -404,11 +425,11 @@ lldb::DisassemblerSP Function::GetInstructions(const ExecutionContext &exe_ctx, const char *flavor, bool prefer_file_cache) { ModuleSP module_sp(GetAddressRange().GetBaseAddress().GetModule()); - if (module_sp) { + if (module_sp && exe_ctx.HasTargetScope()) { const bool prefer_file_cache = false; return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr, - flavor, exe_ctx, GetAddressRange(), - prefer_file_cache); + flavor, exe_ctx.GetTargetRef(), + GetAddressRange(), prefer_file_cache); } return lldb::DisassemblerSP(); } @@ -465,7 +486,7 @@ bool Function::IsTopLevelFunction() { } ConstString Function::GetDisplayName() const { - return m_mangled.GetDisplayDemangledName(GetLanguage()); + return m_mangled.GetDisplayDemangledName(); } CompilerDeclContext Function::GetDeclContext() { @@ -633,15 +654,9 @@ lldb::LanguageType Function::GetLanguage() const { } ConstString Function::GetName() const { - LanguageType language = lldb::eLanguageTypeUnknown; - if (m_comp_unit) - language = m_comp_unit->GetLanguage(); - return m_mangled.GetName(language); + return m_mangled.GetName(); } ConstString Function::GetNameNoArguments() const { - LanguageType language = lldb::eLanguageTypeUnknown; - if (m_comp_unit) - language = m_comp_unit->GetLanguage(); - return m_mangled.GetName(language, Mangled::ePreferDemangledWithoutArguments); + return m_mangled.GetName(Mangled::ePreferDemangledWithoutArguments); } diff --git a/lldb/source/Symbol/LineEntry.cpp b/lldb/source/Symbol/LineEntry.cpp index bb3828fef784..a3907f4dd9c0 100644 --- a/lldb/source/Symbol/LineEntry.cpp +++ b/lldb/source/Symbol/LineEntry.cpp @@ -1,4 +1,4 @@ -//===-- LineEntry.cpp -------------------------------------------*- C++ -*-===// +//===-- LineEntry.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/LineTable.cpp b/lldb/source/Symbol/LineTable.cpp index fecc90c409f2..19c39bd0aeb5 100644 --- a/lldb/source/Symbol/LineTable.cpp +++ b/lldb/source/Symbol/LineTable.cpp @@ -1,4 +1,4 @@ -//===-- LineTable.cpp -------------------------------------------*- C++ -*-===// +//===-- LineTable.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -21,6 +21,18 @@ using namespace lldb_private; LineTable::LineTable(CompileUnit *comp_unit) : m_comp_unit(comp_unit), m_entries() {} +LineTable::LineTable(CompileUnit *comp_unit, + std::vector<std::unique_ptr<LineSequence>> &&sequences) + : m_comp_unit(comp_unit), m_entries() { + LineTable::Entry::LessThanBinaryPredicate less_than_bp(this); + llvm::stable_sort(sequences, less_than_bp); + for (const auto &sequence : sequences) { + LineSequenceImpl *seq = static_cast<LineSequenceImpl *>(sequence.get()); + m_entries.insert(m_entries.end(), seq->m_entries.begin(), + seq->m_entries.end()); + } +} + // Destructor LineTable::~LineTable() {} @@ -50,8 +62,8 @@ LineSequence::LineSequence() {} void LineTable::LineSequenceImpl::Clear() { m_entries.clear(); } -LineSequence *LineTable::CreateLineSequenceContainer() { - return new LineTable::LineSequenceImpl(); +std::unique_ptr<LineSequence> LineTable::CreateLineSequenceContainer() { + return std::make_unique<LineTable::LineSequenceImpl>(); } void LineTable::AppendLineEntryToSequence( @@ -154,6 +166,14 @@ operator()(const LineTable::Entry &a, const LineTable::Entry &b) const { #undef LT_COMPARE } +bool LineTable::Entry::LessThanBinaryPredicate:: +operator()(const std::unique_ptr<LineSequence> &sequence_a, + const std::unique_ptr<LineSequence> &sequence_b) const { + auto *seq_a = static_cast<const LineSequenceImpl *>(sequence_a.get()); + auto *seq_b = static_cast<const LineSequenceImpl *>(sequence_b.get()); + return (*this)(seq_a->m_entries.front(), seq_b->m_entries.front()); +} + uint32_t LineTable::GetSize() const { return m_entries.size(); } bool LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry) { diff --git a/lldb/source/Symbol/LocateSymbolFile.cpp b/lldb/source/Symbol/LocateSymbolFile.cpp index d2b39d6acd70..95ae2ca7917a 100644 --- a/lldb/source/Symbol/LocateSymbolFile.cpp +++ b/lldb/source/Symbol/LocateSymbolFile.cpp @@ -1,4 +1,4 @@ -//===-- LocateSymbolFile.cpp ------------------------------------*- C++ -*-===// +//===-- LocateSymbolFile.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp b/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp index 5ee632ec2077..251605085c58 100644 --- a/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp +++ b/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp @@ -1,4 +1,4 @@ -//===-- LocateSymbolFileMacOSX.cpp ------------------------------*- C++ -*-===// +//===-- LocateSymbolFileMacOSX.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -253,48 +253,34 @@ int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, const lldb_private::UUID *uuid, const ArchSpec *arch) { - char path[PATH_MAX]; - if (dsym_bundle_fspec.GetPath(path, sizeof(path)) == 0) - return {}; - - ::strncat(path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1); - - DIR *dirp = opendir(path); - if (!dirp) - return {}; - - // Make sure we close the directory before exiting this scope. - auto cleanup_dir = llvm::make_scope_exit([&]() { closedir(dirp); }); - - FileSpec dsym_fspec; - dsym_fspec.GetDirectory().SetCString(path); - struct dirent *dp; - while ((dp = readdir(dirp)) != NULL) { - // Only search directories - if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { - if (dp->d_namlen == 1 && dp->d_name[0] == '.') - continue; - - if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') - continue; - } - - if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) { - dsym_fspec.GetFilename().SetCString(dp->d_name); - ModuleSpecList module_specs; - if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) { - ModuleSpec spec; - for (size_t i = 0; i < module_specs.GetSize(); ++i) { - bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); - UNUSED_IF_ASSERT_DISABLED(got_spec); - assert(got_spec); - if ((uuid == NULL || - (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && - (arch == NULL || - (spec.GetArchitecturePtr() && - spec.GetArchitecture().IsCompatibleMatch(*arch)))) { - return dsym_fspec; - } + std::string dsym_bundle_path = dsym_bundle_fspec.GetPath(); + llvm::SmallString<128> buffer(dsym_bundle_path); + llvm::sys::path::append(buffer, "Contents", "Resources", "DWARF"); + + std::error_code EC; + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = + FileSystem::Instance().GetVirtualFileSystem(); + llvm::vfs::recursive_directory_iterator Iter(*vfs, buffer.str(), EC); + llvm::vfs::recursive_directory_iterator End; + for (; Iter != End && !EC; Iter.increment(EC)) { + llvm::ErrorOr<llvm::vfs::Status> Status = vfs->status(Iter->path()); + if (Status->isDirectory()) + continue; + + FileSpec dsym_fspec(Iter->path()); + ModuleSpecList module_specs; + if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) { + ModuleSpec spec; + for (size_t i = 0; i < module_specs.GetSize(); ++i) { + bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); + assert(got_spec); // The call has side-effects so can't be inlined. + UNUSED_IF_ASSERT_DISABLED(got_spec); + if ((uuid == nullptr || + (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && + (arch == nullptr || + (spec.GetArchitecturePtr() && + spec.GetArchitecture().IsCompatibleMatch(*arch)))) { + return dsym_fspec; } } } diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp index 8a72b5fe6f67..6b552dd0c19e 100644 --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -1,4 +1,4 @@ -//===-- ObjectFile.cpp ------------------------------------------*- C++ -*-===// +//===-- ObjectFile.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -47,8 +47,8 @@ ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, const FileSpec *file, FileSpec archive_file; ObjectContainerCreateInstance create_object_container_callback; - const bool file_exists = FileSystem::Instance().Exists(*file); if (!data_sp) { + const bool file_exists = FileSystem::Instance().Exists(*file); // We have an object name which most likely means we have a .o file in // a static archive (.a file). Try and see if we have a cached archive // first without reading any data first @@ -207,9 +207,11 @@ ObjectFileSP ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, size_t ObjectFile::GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset, lldb::offset_t file_size, - ModuleSpecList &specs) { - DataBufferSP data_sp = - FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512, file_offset); + ModuleSpecList &specs, + DataBufferSP data_sp) { + if (!data_sp) + data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512, + file_offset); if (data_sp) { if (file_size == 0) { const lldb::offset_t actual_file_size = @@ -367,6 +369,7 @@ AddressClass ObjectFile::GetAddressClass(addr_t file_addr) { case eSectionTypeDWARFDebugStrDwo: case eSectionTypeDWARFDebugStrOffsets: case eSectionTypeDWARFDebugStrOffsetsDwo: + case eSectionTypeDWARFDebugTuIndex: case eSectionTypeDWARFDebugTypes: case eSectionTypeDWARFDebugTypesDwo: case eSectionTypeDWARFAppleNames: diff --git a/lldb/source/Symbol/PostfixExpression.cpp b/lldb/source/Symbol/PostfixExpression.cpp index 8ecd571ed929..588b3f92c3f4 100644 --- a/lldb/source/Symbol/PostfixExpression.cpp +++ b/lldb/source/Symbol/PostfixExpression.cpp @@ -1,4 +1,4 @@ -//===-- PostfixExpression.cpp -----------------------------------*- C++ -*-===// +//===-- PostfixExpression.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp index 3ace153d32ab..8d099e0cc7e1 100644 --- a/lldb/source/Symbol/Symbol.cpp +++ b/lldb/source/Symbol/Symbol.cpp @@ -1,4 +1,4 @@ -//===-- Symbol.cpp ----------------------------------------------*- C++ -*-===// +//===-- Symbol.cpp --------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -120,7 +120,7 @@ bool Symbol::ValueIsAddress() const { } ConstString Symbol::GetDisplayName() const { - return m_mangled.GetDisplayDemangledName(GetLanguage()); + return m_mangled.GetDisplayDemangledName(); } ConstString Symbol::GetReExportedSymbolName() const { @@ -203,7 +203,7 @@ void Symbol::GetDescription(Stream *s, lldb::DescriptionLevel level, s->Printf(", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset()); } - ConstString demangled = m_mangled.GetDemangledName(GetLanguage()); + ConstString demangled = m_mangled.GetDemangledName(); if (demangled) s->Printf(", name=\"%s\"", demangled.AsCString()); if (m_mangled.GetMangledName()) @@ -219,7 +219,7 @@ void Symbol::Dump(Stream *s, Target *target, uint32_t index, // Make sure the size of the symbol is up to date before dumping GetByteSize(); - ConstString name = m_mangled.GetName(GetLanguage(), name_preference); + ConstString name = m_mangled.GetName(name_preference); if (ValueIsAddress()) { if (!m_addr_range.GetBaseAddress().Dump(s, nullptr, Address::DumpStyleFileAddress)) @@ -333,7 +333,7 @@ uint32_t Symbol::GetPrologueByteSize() { bool Symbol::Compare(ConstString name, SymbolType type) const { if (type == eSymbolTypeAny || m_type == type) return m_mangled.GetMangledName() == name || - m_mangled.GetDemangledName(GetLanguage()) == name; + m_mangled.GetDemangledName() == name; return false; } @@ -496,11 +496,10 @@ lldb::addr_t Symbol::GetLoadAddress(Target *target) const { return LLDB_INVALID_ADDRESS; } -ConstString Symbol::GetName() const { return m_mangled.GetName(GetLanguage()); } +ConstString Symbol::GetName() const { return m_mangled.GetName(); } ConstString Symbol::GetNameNoArguments() const { - return m_mangled.GetName(GetLanguage(), - Mangled::ePreferDemangledWithoutArguments); + return m_mangled.GetName(Mangled::ePreferDemangledWithoutArguments); } lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const { @@ -542,11 +541,11 @@ lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx, const char *flavor, bool prefer_file_cache) { ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule()); - if (module_sp) { + if (module_sp && exe_ctx.HasTargetScope()) { const bool prefer_file_cache = false; return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr, - flavor, exe_ctx, m_addr_range, - prefer_file_cache); + flavor, exe_ctx.GetTargetRef(), + m_addr_range, prefer_file_cache); } return lldb::DisassemblerSP(); } diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp index 9eb805976f95..12c2077154b9 100644 --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -1,4 +1,4 @@ -//===-- SymbolContext.cpp ---------------------------------------*- C++ -*-===// +//===-- SymbolContext.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -117,9 +117,7 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope, Block *inlined_block = block->GetContainingInlinedBlock(); const InlineFunctionInfo *inlined_block_info = inlined_block->GetInlinedFunctionInfo(); - s->Printf( - " [inlined] %s", - inlined_block_info->GetName(function->GetLanguage()).GetCString()); + s->Printf(" [inlined] %s", inlined_block_info->GetName().GetCString()); lldb_private::AddressRange block_range; if (inlined_block->GetRangeContainingAddress(addr, block_range)) { @@ -657,12 +655,12 @@ SymbolContext::GetFunctionName(Mangled::NamePreference preference) const { const InlineFunctionInfo *inline_info = inlined_block->GetInlinedFunctionInfo(); if (inline_info) - return inline_info->GetName(function->GetLanguage()); + return inline_info->GetName(); } } - return function->GetMangled().GetName(function->GetLanguage(), preference); + return function->GetMangled().GetName(preference); } else if (symbol && symbol->ValueIsAddress()) { - return symbol->GetMangled().GetName(symbol->GetLanguage(), preference); + return symbol->GetMangled().GetName(preference); } else { // No function, return an empty string. return ConstString(); @@ -970,7 +968,7 @@ bool SymbolContextSpecifier::AddSpecification(const char *spec_string, // CompUnits can't necessarily be resolved here, since an inlined function // might show up in a number of CompUnits. Instead we just convert to a // FileSpec and store it away. - m_file_spec_up.reset(new FileSpec(spec_string)); + m_file_spec_up = std::make_unique<FileSpec>(spec_string); m_type |= eFileSpecified; break; case eLineStartSpecified: @@ -1076,19 +1074,17 @@ bool SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc) { if (inline_info != nullptr) { was_inlined = true; const Mangled &name = inline_info->GetMangled(); - if (!name.NameMatches(func_name, sc.function->GetLanguage())) + if (!name.NameMatches(func_name)) return false; } } // If it wasn't inlined, check the name in the function or symbol: if (!was_inlined) { if (sc.function != nullptr) { - if (!sc.function->GetMangled().NameMatches(func_name, - sc.function->GetLanguage())) + if (!sc.function->GetMangled().NameMatches(func_name)) return false; } else if (sc.symbol != nullptr) { - if (!sc.symbol->GetMangled().NameMatches(func_name, - sc.symbol->GetLanguage())) + if (!sc.symbol->GetMangled().NameMatches(func_name)) return false; } } diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp index 90f7d1011716..3f9cdefc8d41 100644 --- a/lldb/source/Symbol/SymbolFile.cpp +++ b/lldb/source/Symbol/SymbolFile.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFile.cpp ------------------------------------------*- C++ -*-===// +//===-- SymbolFile.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -105,7 +105,7 @@ uint32_t SymbolFile::ResolveSymbolContext(const FileSpec &file_spec, } void SymbolFile::FindGlobalVariables(ConstString name, - const CompilerDeclContext *parent_decl_ctx, + const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, VariableList &variables) {} @@ -114,7 +114,7 @@ void SymbolFile::FindGlobalVariables(const RegularExpression ®ex, VariableList &variables) {} void SymbolFile::FindFunctions(ConstString name, - const CompilerDeclContext *parent_decl_ctx, + const CompilerDeclContext &parent_decl_ctx, lldb::FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) {} @@ -130,7 +130,7 @@ void SymbolFile::GetMangledNamesForFunction( } void SymbolFile::FindTypes( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) {} diff --git a/lldb/source/Symbol/SymbolVendor.cpp b/lldb/source/Symbol/SymbolVendor.cpp index 1e1dea71d7f3..0a5acbc48eb4 100644 --- a/lldb/source/Symbol/SymbolVendor.cpp +++ b/lldb/source/Symbol/SymbolVendor.cpp @@ -1,4 +1,4 @@ -//===-- SymbolVendor.cpp ----------------------------------------*- C++ -*-===// +//===-- SymbolVendor.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -51,7 +51,7 @@ SymbolVendor *SymbolVendor::FindPlugin(const lldb::ModuleSP &module_sp, } if (!sym_objfile_sp) sym_objfile_sp = module_sp->GetObjectFile()->shared_from_this(); - instance_up.reset(new SymbolVendor(module_sp)); + instance_up = std::make_unique<SymbolVendor>(module_sp); instance_up->AddSymbolFileRepresentation(sym_objfile_sp); return instance_up.release(); } diff --git a/lldb/source/Symbol/Symtab.cpp b/lldb/source/Symbol/Symtab.cpp index f5bd22ee5ee2..3f697e6076b3 100644 --- a/lldb/source/Symbol/Symtab.cpp +++ b/lldb/source/Symbol/Symtab.cpp @@ -1,4 +1,4 @@ -//===-- Symtab.cpp ----------------------------------------------*- C++ -*-===// +//===-- Symtab.cpp --------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -299,7 +299,7 @@ void Symtab::InitNameIndexes() { // Symbol name strings that didn't match a Mangled::ManglingScheme, are // stored in the demangled field. - if (ConstString name = mangled.GetDemangledName(symbol->GetLanguage())) { + if (ConstString name = mangled.GetDemangledName()) { m_name_to_index.Append(name, value); if (symbol->ContainsLinkerAnnotations()) { @@ -425,7 +425,7 @@ void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes, const Mangled &mangled = symbol->GetMangled(); if (add_demangled) { - if (ConstString name = mangled.GetDemangledName(symbol->GetLanguage())) + if (ConstString name = mangled.GetDemangledName()) name_to_index_map.Append(name, value); } diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index f194356a0a07..307e99ac84b6 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -1,4 +1,4 @@ -//===-- Type.cpp ------------------------------------------------*- C++ -*-===// +//===-- Type.cpp ----------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -143,15 +143,14 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name, llvm::Optional<uint64_t> byte_size, SymbolContextScope *context, user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_type, - ResolveState compiler_type_resolve_state) + ResolveState compiler_type_resolve_state, uint32_t opaque_payload) : std::enable_shared_from_this<Type>(), UserID(uid), m_name(name), m_symbol_file(symbol_file), m_context(context), m_encoding_type(nullptr), m_encoding_uid(encoding_uid), m_encoding_uid_type(encoding_uid_type), m_decl(decl), m_compiler_type(compiler_type), - m_compiler_type_resolve_state( - compiler_type ? compiler_type_resolve_state - : ResolveState::Unresolved), - m_is_complete_objc_class(false) { + m_compiler_type_resolve_state(compiler_type ? compiler_type_resolve_state + : ResolveState::Unresolved), + m_payload(opaque_payload) { if (byte_size) { m_byte_size = *byte_size; m_byte_size_has_value = true; @@ -235,7 +234,7 @@ void Type::GetDescription(Stream *s, lldb::DescriptionLevel level, } } -void Type::Dump(Stream *s, bool show_context) { +void Type::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) { s->Printf("%p: ", static_cast<void *>(this)); s->Indent(); *s << "Type" << static_cast<const UserID &>(*this) << ' '; @@ -256,7 +255,7 @@ void Type::Dump(Stream *s, bool show_context) { if (m_compiler_type.IsValid()) { *s << ", compiler_type = " << m_compiler_type.GetOpaqueQualType() << ' '; - GetForwardCompilerType().DumpTypeDescription(s); + GetForwardCompilerType().DumpTypeDescription(s, level); } else if (m_encoding_uid != LLDB_INVALID_UID) { s->Format(", type_data = {0:x-16}", m_encoding_uid); switch (m_encoding_uid_type) { @@ -303,7 +302,7 @@ void Type::Dump(Stream *s, bool show_context) { ConstString Type::GetName() { if (!m_name) - m_name = GetForwardCompilerType().GetConstTypeName(); + m_name = GetForwardCompilerType().GetTypeName(); return m_name; } @@ -313,7 +312,7 @@ void Type::DumpValue(ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, uint32_t data_byte_offset, bool show_types, bool show_summary, bool verbose, lldb::Format format) { - if (ResolveClangType(ResolveState::Forward)) { + if (ResolveCompilerType(ResolveState::Forward)) { if (show_types) { s->PutChar('('); if (verbose) @@ -466,7 +465,7 @@ bool Type::WriteToMemory(ExecutionContext *exe_ctx, lldb::addr_t addr, const Declaration &Type::GetDeclaration() const { return m_decl; } -bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { +bool Type::ResolveCompilerType(ResolveState compiler_type_resolve_state) { // TODO: This needs to consider the correct type system to use. Type *encoding_type = nullptr; if (!m_compiler_type.IsValid()) { @@ -506,7 +505,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { case eEncodingIsTypedefUID: m_compiler_type = encoding_type->GetForwardCompilerType().CreateTypedef( m_name.AsCString("__lldb_invalid_typedef_name"), - GetSymbolFile()->GetDeclContextContainingUID(GetID())); + GetSymbolFile()->GetDeclContextContainingUID(GetID()), m_payload); m_name.Clear(); break; @@ -536,7 +535,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { LLDB_LOG_ERROR( lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS), std::move(err), - "Unable to construct void type from ClangASTContext"); + "Unable to construct void type from TypeSystemClang"); } else { CompilerType void_compiler_type = type_system_or_err->GetBasicTypeFromAST(eBasicTypeVoid); @@ -564,7 +563,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { case eEncodingIsTypedefUID: m_compiler_type = void_compiler_type.CreateTypedef( m_name.AsCString("__lldb_invalid_typedef_name"), - GetSymbolFile()->GetDeclContextContainingUID(GetID())); + GetSymbolFile()->GetDeclContextContainingUID(GetID()), m_payload); break; case eEncodingIsPointerUID: @@ -627,7 +626,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { break; } } - encoding_type->ResolveClangType(encoding_compiler_type_resolve_state); + encoding_type->ResolveCompilerType(encoding_compiler_type_resolve_state); } } return m_compiler_type.IsValid(); @@ -642,22 +641,22 @@ uint32_t Type::GetEncodingMask() { } CompilerType Type::GetFullCompilerType() { - ResolveClangType(ResolveState::Full); + ResolveCompilerType(ResolveState::Full); return m_compiler_type; } CompilerType Type::GetLayoutCompilerType() { - ResolveClangType(ResolveState::Layout); + ResolveCompilerType(ResolveState::Layout); return m_compiler_type; } CompilerType Type::GetForwardCompilerType() { - ResolveClangType(ResolveState::Forward); + ResolveCompilerType(ResolveState::Forward); return m_compiler_type; } ConstString Type::GetQualifiedName() { - return GetForwardCompilerType().GetConstTypeName(); + return GetForwardCompilerType().GetTypeName(); } bool Type::GetTypeScopeAndBasename(const llvm::StringRef& name, diff --git a/lldb/source/Symbol/TypeList.cpp b/lldb/source/Symbol/TypeList.cpp index 1813e8ecca9a..f0506c7c5bfc 100644 --- a/lldb/source/Symbol/TypeList.cpp +++ b/lldb/source/Symbol/TypeList.cpp @@ -1,4 +1,4 @@ -//===-- TypeList.cpp --------------------------------------------*- C++ -*-===// +//===-- TypeList.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -107,7 +107,8 @@ void TypeList::RemoveMismatchedTypes(const char *qualified_typename, type_basename = qualified_typename; type_scope = ""; } - return RemoveMismatchedTypes(type_scope, type_basename, type_class, + return RemoveMismatchedTypes(std::string(type_scope), + std::string(type_basename), type_class, exact_match); } diff --git a/lldb/source/Symbol/TypeMap.cpp b/lldb/source/Symbol/TypeMap.cpp index 4ee1026bed24..e810d3020073 100644 --- a/lldb/source/Symbol/TypeMap.cpp +++ b/lldb/source/Symbol/TypeMap.cpp @@ -1,4 +1,4 @@ -//===-- TypeMap.cpp --------------------------------------------*- C++ -*-===// +//===-- TypeMap.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -121,9 +121,9 @@ bool TypeMap::Remove(const lldb::TypeSP &type_sp) { return false; } -void TypeMap::Dump(Stream *s, bool show_context) { +void TypeMap::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) { for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) { - pos->second->Dump(s, show_context); + pos->second->Dump(s, show_context, level); } } @@ -137,7 +137,8 @@ void TypeMap::RemoveMismatchedTypes(const char *qualified_typename, type_basename = qualified_typename; type_scope = ""; } - return RemoveMismatchedTypes(type_scope, type_basename, type_class, + return RemoveMismatchedTypes(std::string(type_scope), + std::string(type_basename), type_class, exact_match); } diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index 29a49a6fb1d4..5e57813c28bd 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -1,4 +1,4 @@ -//===-- TypeSystem.cpp ------------------------------------------*- C++ -*-===// +//===-- TypeSystem.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -70,6 +70,10 @@ lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language, return CreateInstanceHelper(language, nullptr, target); } +#ifndef NDEBUG +bool TypeSystem::Verify(lldb::opaque_compiler_type_t type) { return true; } +#endif + bool TypeSystem::IsAnonymousType(lldb::opaque_compiler_type_t type) { return false; } @@ -109,7 +113,8 @@ TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) { CompilerType TypeSystem::CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, - const CompilerDeclContext &decl_ctx) { + const CompilerDeclContext &decl_ctx, + uint32_t opaque_payload) { return CompilerType(); } @@ -239,7 +244,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } error = llvm::make_error<llvm::StringError>( "TypeSystem for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)) + + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", llvm::inconvertibleErrorCode()); return std::move(error); @@ -256,7 +261,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } error = llvm::make_error<llvm::StringError>( "TypeSystem for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)) + + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", llvm::inconvertibleErrorCode()); return std::move(error); @@ -266,7 +271,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, if (!can_create) { error = llvm::make_error<llvm::StringError>( "Unable to find type system for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)), + llvm::StringRef(Language::GetNameForLanguageType(language)), llvm::inconvertibleErrorCode()); } else { // Cache even if we get a shared pointer that contains a null type system @@ -279,7 +284,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } error = llvm::make_error<llvm::StringError>( "TypeSystem for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)) + + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", llvm::inconvertibleErrorCode()); } @@ -308,7 +313,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } error = llvm::make_error<llvm::StringError>( "TypeSystem for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)) + + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", llvm::inconvertibleErrorCode()); return std::move(error); @@ -325,7 +330,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } error = llvm::make_error<llvm::StringError>( "TypeSystem for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)) + + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", llvm::inconvertibleErrorCode()); return std::move(error); @@ -335,7 +340,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, if (!can_create) { error = llvm::make_error<llvm::StringError>( "Unable to find type system for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)), + llvm::StringRef(Language::GetNameForLanguageType(language)), llvm::inconvertibleErrorCode()); } else { // Cache even if we get a shared pointer that contains a null type system @@ -348,7 +353,7 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } error = llvm::make_error<llvm::StringError>( "TypeSystem for language " + - llvm::toStringRef(Language::GetNameForLanguageType(language)) + + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", llvm::inconvertibleErrorCode()); } diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp index 15443ce5d8ac..e8906f38e2ff 100644 --- a/lldb/source/Symbol/UnwindPlan.cpp +++ b/lldb/source/Symbol/UnwindPlan.cpp @@ -1,4 +1,4 @@ -//===-- UnwindPlan.cpp ----------------------------------*- C++ -*-===// +//===-- UnwindPlan.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,6 +15,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" using namespace lldb; using namespace lldb_private; @@ -79,13 +80,10 @@ GetByteOrderAndAddrSize(Thread *thread) { static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) { if (auto order_and_width = GetByteOrderAndAddrSize(thread)) { - DataExtractor extractor(expr.data(), expr.size(), order_and_width->first, - order_and_width->second); - if (!DWARFExpression::PrintDWARFExpression(s, extractor, - order_and_width->second, - /*dwarf_ref_size*/ 4, - /*location_expression*/ false)) - s.PutCString("invalid-dwarf-expr"); + llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle, + order_and_width->second); + llvm::DWARFExpression(data, order_and_width->second, llvm::dwarf::DWARF32) + .print(s.AsRawOstream(), nullptr, nullptr); } else s.PutCString("dwarf-expr"); } diff --git a/lldb/source/Symbol/UnwindTable.cpp b/lldb/source/Symbol/UnwindTable.cpp index 045957a67b3b..3faa528a339f 100644 --- a/lldb/source/Symbol/UnwindTable.cpp +++ b/lldb/source/Symbol/UnwindTable.cpp @@ -1,4 +1,4 @@ -//===-- UnwindTable.cpp -----------------------------------------*- C++ -*-===// +//===-- UnwindTable.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -57,26 +57,28 @@ void UnwindTable::Initialize() { SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true); if (sect.get()) { - m_eh_frame_up.reset( - new DWARFCallFrameInfo(*object_file, sect, DWARFCallFrameInfo::EH)); + m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>( + *object_file, sect, DWARFCallFrameInfo::EH); } sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true); if (sect) { - m_debug_frame_up.reset( - new DWARFCallFrameInfo(*object_file, sect, DWARFCallFrameInfo::DWARF)); + m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>( + *object_file, sect, DWARFCallFrameInfo::DWARF); } sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true); if (sect) { - m_compact_unwind_up.reset(new CompactUnwindInfo(*object_file, sect)); + m_compact_unwind_up = + std::make_unique<CompactUnwindInfo>(*object_file, sect); } sect = sl->FindSectionByType(eSectionTypeARMexidx, true); if (sect) { SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true); if (sect_extab.get()) { - m_arm_unwind_up.reset(new ArmUnwindInfo(*object_file, sect, sect_extab)); + m_arm_unwind_up = + std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab); } } } diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp index a0496824a0a3..6c18ef15e1a2 100644 --- a/lldb/source/Symbol/Variable.cpp +++ b/lldb/source/Symbol/Variable.cpp @@ -1,4 +1,4 @@ -//===-- Variable.cpp --------------------------------------------*- C++ -*-===// +//===-- Variable.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -68,7 +68,7 @@ lldb::LanguageType Variable::GetLanguage() const { } ConstString Variable::GetName() const { - ConstString name = m_mangled.GetName(GetLanguage()); + ConstString name = m_mangled.GetName(); if (name) return name; return m_name; @@ -82,16 +82,13 @@ bool Variable::NameMatches(ConstString name) const { SymbolContext variable_sc; m_owner_scope->CalculateSymbolContext(&variable_sc); - LanguageType language = eLanguageTypeUnknown; - if (variable_sc.comp_unit) - language = variable_sc.comp_unit->GetLanguage(); - return m_mangled.NameMatches(name, language); + return m_mangled.NameMatches(name); } bool Variable::NameMatches(const RegularExpression ®ex) const { if (regex.Execute(m_name.AsCString())) return true; if (m_mangled) - return m_mangled.NameMatches(regex, GetLanguage()); + return m_mangled.NameMatches(regex); return false; } @@ -532,7 +529,7 @@ static void PrivateAutoCompleteMembers( i, member_name, nullptr, nullptr, nullptr); if (partial_member_name.empty() || - member_name.find(partial_member_name) == 0) { + llvm::StringRef(member_name).startswith(partial_member_name)) { if (member_name == partial_member_name) { PrivateAutoComplete( frame, partial_path, @@ -684,8 +681,8 @@ static void PrivateAutoComplete( break; } - std::string token(partial_path, 0, pos); - remaining_partial_path = partial_path.substr(pos); + std::string token(std::string(partial_path), 0, pos); + remaining_partial_path = std::string(partial_path.substr(pos)); if (compiler_type.IsValid()) { PrivateAutoCompleteMembers(frame, token, remaining_partial_path, diff --git a/lldb/source/Symbol/VariableList.cpp b/lldb/source/Symbol/VariableList.cpp index 51312472e265..f7a441472bc0 100644 --- a/lldb/source/Symbol/VariableList.cpp +++ b/lldb/source/Symbol/VariableList.cpp @@ -1,4 +1,4 @@ -//===-- VariableList.cpp ----------------------------------------*- C++ -*-===// +//===-- VariableList.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. |