diff options
Diffstat (limited to 'source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp')
-rw-r--r-- | source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp | 665 |
1 files changed, 665 insertions, 0 deletions
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp new file mode 100644 index 000000000000..cd6ece297ed1 --- /dev/null +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -0,0 +1,665 @@ +//===-- AppleObjCDeclVendor.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AppleObjCDeclVendor.h" + +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "Plugins/ExpressionParser/Clang/ASTDumper.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" + +using namespace lldb_private; + +class lldb_private::AppleObjCExternalASTSource : public ClangExternalASTSourceCommon +{ +public: + AppleObjCExternalASTSource (AppleObjCDeclVendor &decl_vendor) : + m_decl_vendor(decl_vendor) + { + } + + bool + FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx, clang::DeclarationName name) override + { + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + + if (log) + { + log->Printf("AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p", + current_id, + static_cast<void*>(&decl_ctx->getParentASTContext()), + name.getAsString().c_str(), decl_ctx->getDeclKindName(), + static_cast<const void*>(decl_ctx)); + } + + do + { + const clang::ObjCInterfaceDecl *interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx); + + if (!interface_decl) + break; + + clang::ObjCInterfaceDecl *non_const_interface_decl = const_cast<clang::ObjCInterfaceDecl*>(interface_decl); + + if (!m_decl_vendor.FinishDecl(non_const_interface_decl)) + break; + + clang::DeclContext::lookup_result result = non_const_interface_decl->lookup(name); + + return (result.size() != 0); + } + while(0); + + SetNoExternalVisibleDeclsForName(decl_ctx, name); + return false; + } + + void + CompleteType(clang::TagDecl *tag_decl) override + { + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + + if (log) + { + log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s", + current_id, + static_cast<void*>(&tag_decl->getASTContext()), + static_cast<void*>(tag_decl), + tag_decl->getName().str().c_str()); + + log->Printf(" AOEAS::CT[%u] Before:", current_id); + ASTDumper dumper((clang::Decl*)tag_decl); + dumper.ToLog(log, " [CT] "); + } + + if (log) + { + log->Printf(" AOEAS::CT[%u] After:", current_id); + ASTDumper dumper((clang::Decl*)tag_decl); + dumper.ToLog(log, " [CT] "); + } + return; + } + + void + CompleteType(clang::ObjCInterfaceDecl *interface_decl) override + { + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + + if (log) + { + log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s", + current_id, + static_cast<void*>(&interface_decl->getASTContext()), + static_cast<void*>(interface_decl), + interface_decl->getName().str().c_str()); + + log->Printf(" AOEAS::CT[%u] Before:", current_id); + ASTDumper dumper((clang::Decl*)interface_decl); + dumper.ToLog(log, " [CT] "); + } + + m_decl_vendor.FinishDecl(interface_decl); + + if (log) + { + log->Printf(" [CT] After:"); + ASTDumper dumper((clang::Decl*)interface_decl); + dumper.ToLog(log, " [CT] "); + } + return; + } + + bool + 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) override + { + return false; + } + + void + StartTranslationUnit(clang::ASTConsumer *Consumer) override + { + clang::TranslationUnitDecl *translation_unit_decl = m_decl_vendor.m_ast_ctx.getASTContext()->getTranslationUnitDecl(); + translation_unit_decl->setHasExternalVisibleStorage(); + translation_unit_decl->setHasExternalLexicalStorage(); + } +private: + AppleObjCDeclVendor &m_decl_vendor; +}; + +AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime) : + DeclVendor(), + m_runtime(runtime), + m_ast_ctx(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()), + m_type_realizer_sp(m_runtime.GetEncodingToType()) +{ + m_external_source = new AppleObjCExternalASTSource (*this); + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr (m_external_source); + m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr); +} + +clang::ObjCInterfaceDecl* +AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) +{ + ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa); + + if (iter != m_isa_to_interface.end()) + return iter->second; + + clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); + + ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(isa); + + if (!descriptor) + return NULL; + + const ConstString &name(descriptor->GetClassName()); + + clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef()); + + clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx, + ast_ctx->getTranslationUnitDecl(), + clang::SourceLocation(), + &identifier_info, + nullptr, + nullptr); + + ClangASTMetadata meta_data; + meta_data.SetISAPtr(isa); + m_external_source->SetMetadata(new_iface_decl, meta_data); + + new_iface_decl->setHasExternalVisibleStorage(); + new_iface_decl->setHasExternalLexicalStorage(); + + ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl); + + m_isa_to_interface[isa] = new_iface_decl; + + return new_iface_decl; +} + +class ObjCRuntimeMethodType +{ +public: + ObjCRuntimeMethodType (const char *types) : m_is_valid(false) + { + const char *cursor = types; + enum ParserState { + Start = 0, + InType, + InPos + } state = Start; + const char *type = NULL; + int brace_depth = 0; + + uint32_t stepsLeft = 256; + + while (1) + { + if (--stepsLeft == 0) + { + m_is_valid = false; + return; + } + + switch (state) + { + case Start: + { + switch (*cursor) + { + default: + state = InType; + type = cursor; + break; + case '\0': + m_is_valid = true; + return; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + m_is_valid = false; + return; + } + } + break; + case InType: + { + switch (*cursor) + { + default: + ++cursor; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (!brace_depth) + { + state = InPos; + if (type) + { + m_type_vector.push_back(std::string(type, (cursor - type))); + } + else + { + m_is_valid = false; + return; + } + type = NULL; + } + else + { + ++cursor; + } + break; + case '[': case '{': case '(': + ++brace_depth; + ++cursor; + break; + case ']': case '}': case ')': + if (!brace_depth) + { + m_is_valid = false; + return; + } + --brace_depth; + ++cursor; + break; + case '\0': + m_is_valid = false; + return; + } + } + break; + case InPos: + { + switch (*cursor) + { + default: + state = InType; + type = cursor; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + ++cursor; + break; + case '\0': + m_is_valid = true; + return; + } + } + break; + } + } + } + + clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance, ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) + { + if (!m_is_valid || m_type_vector.size() < 3) + return NULL; + + clang::ASTContext &ast_ctx(interface_decl->getASTContext()); + + clang::QualType return_qual_type; + + const bool isInstance = instance; + const bool isVariadic = false; + const bool isSynthesized = false; + const bool isImplicitlyDeclared = true; + const bool isDefined = false; + const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None; + const bool HasRelatedResultType = false; + const bool for_expression = true; + + std::vector <clang::IdentifierInfo *> selector_components; + + const char *name_cursor = name; + bool is_zero_argument = true; + + + while (*name_cursor != '\0') + { + const char *colon_loc = strchr(name_cursor, ':'); + if (!colon_loc) + { + selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor))); + break; + } + else + { + is_zero_argument = false; + selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor, colon_loc - name_cursor))); + name_cursor = colon_loc + 1; + } + } + + clang::Selector sel = ast_ctx.Selectors.getSelector(is_zero_argument ? 0 : selector_components.size(), selector_components.data()); + + clang::QualType ret_type = ClangASTContext::GetQualType(type_realizer_sp->RealizeType(interface_decl->getASTContext(), m_type_vector[0].c_str(), for_expression)); + + if (ret_type.isNull()) + return NULL; + + clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(ast_ctx, + clang::SourceLocation(), + clang::SourceLocation(), + sel, + ret_type, + NULL, + interface_decl, + isInstance, + isVariadic, + isSynthesized, + isImplicitlyDeclared, + isDefined, + impControl, + HasRelatedResultType); + + std::vector <clang::ParmVarDecl*> parm_vars; + + for (size_t ai = 3, ae = m_type_vector.size(); + ai != ae; + ++ai) + { + const bool for_expression = true; + clang::QualType arg_type = ClangASTContext::GetQualType(type_realizer_sp->RealizeType(ast_ctx, m_type_vector[ai].c_str(), for_expression)); + + if (arg_type.isNull()) + return NULL; // well, we just wasted a bunch of time. Wish we could delete the stuff we'd just made! + + parm_vars.push_back(clang::ParmVarDecl::Create(ast_ctx, + ret, + clang::SourceLocation(), + clang::SourceLocation(), + NULL, + arg_type, + NULL, + clang::SC_None, + NULL)); + } + + ret->setMethodParams(ast_ctx, llvm::ArrayRef<clang::ParmVarDecl*>(parm_vars), llvm::ArrayRef<clang::SourceLocation>()); + + return ret; + } +private: + typedef std::vector <std::string> TypeVector; + + TypeVector m_type_vector; + bool m_is_valid; +}; + +bool +AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) +{ + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + + ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl); + ObjCLanguageRuntime::ObjCISA objc_isa = 0; + if (metadata) + objc_isa = metadata->GetISAPtr(); + + if (!objc_isa) + return false; + + if (!interface_decl->hasExternalVisibleStorage()) + return true; + + interface_decl->startDefinition(); + + interface_decl->setHasExternalVisibleStorage(false); + interface_decl->setHasExternalLexicalStorage(false); + + ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(objc_isa); + + if (!descriptor) + return false; + + auto superclass_func = [interface_decl, this](ObjCLanguageRuntime::ObjCISA isa) + { + clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa); + + if (!superclass_decl) + return; + + FinishDecl(superclass_decl); + clang::ASTContext *context = m_ast_ctx.getASTContext(); + interface_decl->setSuperClass( + context->getTrivialTypeSourceInfo(context->getObjCInterfaceType(superclass_decl))); + }; + + auto instance_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool + { + if (!name || !types) + return false; // skip this one + + ObjCRuntimeMethodType method_type(types); + + clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, true, m_type_realizer_sp); + + if (log) + log->Printf("[ AOTV::FD] Instance method [%s] [%s]", name, types); + + if (method_decl) + interface_decl->addDecl(method_decl); + + return false; + }; + + auto class_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool + { + if (!name || !types) + return false; // skip this one + + ObjCRuntimeMethodType method_type(types); + + clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, false, m_type_realizer_sp); + + if (log) + log->Printf("[ AOTV::FD] Class method [%s] [%s]", name, types); + + if (method_decl) + interface_decl->addDecl(method_decl); + + return false; + }; + + auto ivar_func = [log, interface_decl, this](const char *name, const char *type, lldb::addr_t offset_ptr, uint64_t size) -> bool + { + if (!name || !type) + return false; + + const bool for_expression = false; + + if (log) + log->Printf("[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64, name, type, offset_ptr); + + CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType(m_ast_ctx, type, for_expression); + + if (ivar_type.IsValid()) + { + clang::TypeSourceInfo * const type_source_info = nullptr; + const bool is_synthesized = false; + clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create (*m_ast_ctx.getASTContext(), + interface_decl, + clang::SourceLocation(), + clang::SourceLocation(), + &m_ast_ctx.getASTContext()->Idents.get(name), + ClangASTContext::GetQualType(ivar_type), + type_source_info, // TypeSourceInfo * + clang::ObjCIvarDecl::Public, + 0, + is_synthesized); + + if (ivar_decl) + { + interface_decl->addDecl(ivar_decl); + } + } + + return false; + }; + + if (log) + { + ASTDumper method_dumper ((clang::Decl*)interface_decl); + + log->Printf("[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C interface for %s", descriptor->GetClassName().AsCString()); + } + + + if (!descriptor->Describe(superclass_func, + instance_method_func, + class_method_func, + ivar_func)) + return false; + + if (log) + { + ASTDumper method_dumper ((clang::Decl*)interface_decl); + + log->Printf("[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface"); + + method_dumper.ToLog(log, " [AOTV::FD] "); + } + + return true; +} + +uint32_t +AppleObjCDeclVendor::FindDecls (const ConstString &name, + bool append, + uint32_t max_matches, + std::vector <clang::NamedDecl *> &decls) +{ + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + + if (log) + log->Printf("AppleObjCDeclVendor::FindTypes [%u] ('%s', %s, %u, )", + current_id, + (const char*)name.AsCString(), + append ? "true" : "false", + max_matches); + + if (!append) + decls.clear(); + + uint32_t ret = 0; + + do + { + // See if the type is already in our ASTContext. + + clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); + + clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef()); + clang::DeclarationName decl_name = ast_ctx->DeclarationNames.getIdentifier(&identifier_info); + + clang::DeclContext::lookup_result lookup_result = ast_ctx->getTranslationUnitDecl()->lookup(decl_name); + + if (!lookup_result.empty()) + { + if (clang::ObjCInterfaceDecl *result_iface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) + { + if (log) + { + clang::QualType result_iface_type = ast_ctx->getObjCInterfaceType(result_iface_decl); + ASTDumper dumper(result_iface_type); + + uint64_t isa_value = LLDB_INVALID_ADDRESS; + ClangASTMetadata *metadata = m_external_source->GetMetadata(result_iface_decl); + if (metadata) + isa_value = metadata->GetISAPtr(); + + log->Printf("AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 ") in the ASTContext", + current_id, + dumper.GetCString(), + isa_value); + } + + decls.push_back(result_iface_decl); + ret++; + break; + } + else + { + if (log) + log->Printf("AOCTV::FT [%u] There's something in the ASTContext, but it's not something we know about", + current_id); + break; + } + } + else if(log) + { + log->Printf("AOCTV::FT [%u] Couldn't find %s in the ASTContext", + current_id, + name.AsCString()); + } + + // It's not. If it exists, we have to put it into our ASTContext. + + ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name); + + if (!isa) + { + if (log) + log->Printf("AOCTV::FT [%u] Couldn't find the isa", + current_id); + + break; + } + + clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa); + + if (!iface_decl) + { + if (log) + log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for isa 0x%" PRIx64, + current_id, + (uint64_t)isa); + + break; + } + + if (log) + { + clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(iface_decl); + ASTDumper dumper(new_iface_type); + log->Printf("AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")", + current_id, + dumper.GetCString(), + (uint64_t)isa); + } + + decls.push_back(iface_decl); + ret++; + break; + } while (0); + + return ret; +} |