brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.3 KiB · 60f9893 Raw
612 lines · cpp
1//===-- AppleObjCDeclVendor.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "AppleObjCDeclVendor.h"10 11#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"12#include "Plugins/ExpressionParser/Clang/ClangUtil.h"13#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"14#include "lldb/Core/Module.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/LLDBLog.h"18#include "lldb/Utility/Log.h"19 20#include "clang/AST/ASTContext.h"21#include "clang/AST/DeclObjC.h"22#include "clang/AST/ExternalASTSource.h"23 24using namespace lldb_private;25 26class lldb_private::AppleObjCExternalASTSource27    : public clang::ExternalASTSource {28public:29  AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor)30      : m_decl_vendor(decl_vendor) {}31 32  bool FindExternalVisibleDeclsByName(33      const clang::DeclContext *decl_ctx, clang::DeclarationName name,34      const clang::DeclContext *original_dc) override {35 36    Log *log(GetLog(37        LLDBLog::Expressions)); // FIXME - a more appropriate log channel?38 39    if (log) {40      LLDB_LOGF(log,41                "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName"42                " on (ASTContext*)%p Looking for %s in (%sDecl*)%p",43                static_cast<void *>(&decl_ctx->getParentASTContext()),44                name.getAsString().c_str(), decl_ctx->getDeclKindName(),45                static_cast<const void *>(decl_ctx));46    }47 48    do {49      const clang::ObjCInterfaceDecl *interface_decl =50          llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);51 52      if (!interface_decl)53        break;54 55      clang::ObjCInterfaceDecl *non_const_interface_decl =56          const_cast<clang::ObjCInterfaceDecl *>(interface_decl);57 58      if (!m_decl_vendor.FinishDecl(non_const_interface_decl))59        break;60 61      clang::DeclContext::lookup_result result =62          non_const_interface_decl->lookup(name);63 64      return (!result.empty());65    } while (false);66 67    SetNoExternalVisibleDeclsForName(decl_ctx, name);68    return false;69  }70 71  void CompleteType(clang::TagDecl *tag_decl) override {72 73    Log *log(GetLog(74        LLDBLog::Expressions)); // FIXME - a more appropriate log channel?75 76    LLDB_LOGF(log,77              "AppleObjCExternalASTSource::CompleteType on "78              "(ASTContext*)%p Completing (TagDecl*)%p named %s",79              static_cast<void *>(&tag_decl->getASTContext()),80              static_cast<void *>(tag_decl), tag_decl->getName().str().c_str());81 82    LLDB_LOG(log, "  AOEAS::CT Before:\n{1}", ClangUtil::DumpDecl(tag_decl));83 84    LLDB_LOG(log, "  AOEAS::CT After:{1}", ClangUtil::DumpDecl(tag_decl));85  }86 87  void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override {88 89    Log *log(GetLog(90        LLDBLog::Expressions)); // FIXME - a more appropriate log channel?91 92    if (log) {93      LLDB_LOGF(log,94                "AppleObjCExternalASTSource::CompleteType on "95                "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",96                static_cast<void *>(&interface_decl->getASTContext()),97                static_cast<void *>(interface_decl),98                interface_decl->getName().str().c_str());99 100      LLDB_LOGF(log, "  AOEAS::CT Before:");101      LLDB_LOG(log, "    [CT] {0}", ClangUtil::DumpDecl(interface_decl));102    }103 104    m_decl_vendor.FinishDecl(interface_decl);105 106    if (log) {107      LLDB_LOGF(log, "  [CT] After:");108      LLDB_LOG(log, "    [CT] {0}", ClangUtil::DumpDecl(interface_decl));109    }110  }111 112  bool layoutRecordType(113      const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,114      llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,115      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>116          &BaseOffsets,117      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>118          &VirtualBaseOffsets) override {119    return false;120  }121 122  void StartTranslationUnit(clang::ASTConsumer *Consumer) override {123    clang::TranslationUnitDecl *translation_unit_decl =124        m_decl_vendor.m_ast_ctx->getASTContext().getTranslationUnitDecl();125    translation_unit_decl->setHasExternalVisibleStorage();126    translation_unit_decl->setHasExternalLexicalStorage();127  }128 129private:130  AppleObjCDeclVendor &m_decl_vendor;131};132 133AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime)134    : DeclVendor(eAppleObjCDeclVendor), m_runtime(runtime),135      m_type_realizer_sp(m_runtime.GetEncodingToType()) {136  m_ast_ctx = std::make_shared<TypeSystemClang>(137      "AppleObjCDeclVendor AST",138      runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple());139  auto external_source_owning_ptr =140      llvm::makeIntrusiveRefCnt<AppleObjCExternalASTSource>(*this);141  m_external_source = external_source_owning_ptr.get();142  m_ast_ctx->getASTContext().setExternalSource(external_source_owning_ptr);143}144 145clang::ObjCInterfaceDecl *146AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) {147  ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);148 149  if (iter != m_isa_to_interface.end())150    return iter->second;151 152  clang::ASTContext &ast_ctx = m_ast_ctx->getASTContext();153 154  ObjCLanguageRuntime::ClassDescriptorSP descriptor =155      m_runtime.GetClassDescriptorFromISA(isa);156 157  if (!descriptor)158    return nullptr;159 160  ConstString name(descriptor->GetClassName());161 162  clang::IdentifierInfo &identifier_info =163      ast_ctx.Idents.get(name.GetStringRef());164 165  clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(166      ast_ctx, ast_ctx.getTranslationUnitDecl(), clang::SourceLocation(),167      &identifier_info, nullptr, nullptr);168 169  ClangASTMetadata meta_data;170  meta_data.SetISAPtr(isa);171  m_ast_ctx->SetMetadata(new_iface_decl, meta_data);172 173  new_iface_decl->setHasExternalVisibleStorage();174  new_iface_decl->setHasExternalLexicalStorage();175 176  ast_ctx.getTranslationUnitDecl()->addDecl(new_iface_decl);177 178  m_isa_to_interface[isa] = new_iface_decl;179 180  return new_iface_decl;181}182 183class ObjCRuntimeMethodType {184public:185  ObjCRuntimeMethodType(const char *types) {186    const char *cursor = types;187    enum ParserState { Start = 0, InType, InPos } state = Start;188    const char *type = nullptr;189    int brace_depth = 0;190 191    uint32_t stepsLeft = 256;192 193    while (true) {194      if (--stepsLeft == 0) {195        m_is_valid = false;196        return;197      }198 199      switch (state) {200      case Start: {201        switch (*cursor) {202        default:203          state = InType;204          type = cursor;205          break;206        case '\0':207          m_is_valid = true;208          return;209        case '0':210        case '1':211        case '2':212        case '3':213        case '4':214        case '5':215        case '6':216        case '7':217        case '8':218        case '9':219          m_is_valid = false;220          return;221        }222      } break;223      case InType: {224        switch (*cursor) {225        default:226          ++cursor;227          break;228        case '0':229        case '1':230        case '2':231        case '3':232        case '4':233        case '5':234        case '6':235        case '7':236        case '8':237        case '9':238          if (!brace_depth) {239            state = InPos;240            if (type) {241              m_type_vector.push_back(std::string(type, (cursor - type)));242            } else {243              m_is_valid = false;244              return;245            }246            type = nullptr;247          } else {248            ++cursor;249          }250          break;251        case '[':252        case '{':253        case '(':254          ++brace_depth;255          ++cursor;256          break;257        case ']':258        case '}':259        case ')':260          if (!brace_depth) {261            m_is_valid = false;262            return;263          }264          --brace_depth;265          ++cursor;266          break;267        case '\0':268          m_is_valid = false;269          return;270        }271      } break;272      case InPos: {273        switch (*cursor) {274        default:275          state = InType;276          type = cursor;277          break;278        case '0':279        case '1':280        case '2':281        case '3':282        case '4':283        case '5':284        case '6':285        case '7':286        case '8':287        case '9':288          ++cursor;289          break;290        case '\0':291          m_is_valid = true;292          return;293        }294      } break;295      }296    }297  }298 299  clang::ObjCMethodDecl *300  BuildMethod(TypeSystemClang &clang_ast_ctxt,301              clang::ObjCInterfaceDecl *interface_decl, const char *name,302              bool instance,303              ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) {304    if (!m_is_valid || m_type_vector.size() < 3)305      return nullptr;306 307    clang::ASTContext &ast_ctx(interface_decl->getASTContext());308 309    const bool isInstance = instance;310    const bool isVariadic = false;311    const bool isPropertyAccessor = false;312    const bool isSynthesizedAccessorStub = false;313    const bool isImplicitlyDeclared = true;314    const bool isDefined = false;315    const clang::ObjCImplementationControl impControl =316        clang::ObjCImplementationControl::None;317    const bool HasRelatedResultType = false;318    const bool for_expression = true;319 320    std::vector<const clang::IdentifierInfo *> selector_components;321 322    const char *name_cursor = name;323    bool is_zero_argument = true;324 325    while (*name_cursor != '\0') {326      const char *colon_loc = strchr(name_cursor, ':');327      if (!colon_loc) {328        selector_components.push_back(329            &ast_ctx.Idents.get(llvm::StringRef(name_cursor)));330        break;331      } else {332        is_zero_argument = false;333        selector_components.push_back(&ast_ctx.Idents.get(334            llvm::StringRef(name_cursor, colon_loc - name_cursor)));335        name_cursor = colon_loc + 1;336      }337    }338 339    const clang::IdentifierInfo **identifier_infos = selector_components.data();340    if (!identifier_infos) {341      return nullptr;342    }343 344    clang::Selector sel = ast_ctx.Selectors.getSelector(345        is_zero_argument ? 0 : selector_components.size(),346        identifier_infos);347 348    clang::QualType ret_type =349        ClangUtil::GetQualType(type_realizer_sp->RealizeType(350            clang_ast_ctxt, m_type_vector[0].c_str(), for_expression));351 352    if (ret_type.isNull())353      return nullptr;354 355    clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(356        ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel,357        ret_type, nullptr, interface_decl, isInstance, isVariadic,358        isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared,359        isDefined, impControl, HasRelatedResultType);360 361    std::vector<clang::ParmVarDecl *> parm_vars;362 363    for (size_t ai = 3, ae = m_type_vector.size(); ai != ae; ++ai) {364      const bool for_expression = true;365      clang::QualType arg_type =366          ClangUtil::GetQualType(type_realizer_sp->RealizeType(367              clang_ast_ctxt, m_type_vector[ai].c_str(), for_expression));368 369      if (arg_type.isNull())370        return nullptr; // well, we just wasted a bunch of time.  Wish we could371                        // delete the stuff we'd just made!372 373      parm_vars.push_back(clang::ParmVarDecl::Create(374          ast_ctx, ret, clang::SourceLocation(), clang::SourceLocation(),375          nullptr, arg_type, nullptr, clang::SC_None, nullptr));376    }377 378    ret->setMethodParams(ast_ctx,379                         llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars),380                         llvm::ArrayRef<clang::SourceLocation>());381 382    return ret;383  }384 385  explicit operator bool() { return m_is_valid; }386 387  size_t GetNumTypes() { return m_type_vector.size(); }388 389  const char *GetTypeAtIndex(size_t idx) { return m_type_vector[idx].c_str(); }390 391private:392  typedef std::vector<std::string> TypeVector;393 394  TypeVector m_type_vector;395  bool m_is_valid = false;396};397 398bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) {399  Log *log(400      GetLog(LLDBLog::Expressions)); // FIXME - a more appropriate log channel?401 402  ObjCLanguageRuntime::ObjCISA objc_isa = 0;403  if (std::optional<ClangASTMetadata> metadata =404          m_ast_ctx->GetMetadata(interface_decl))405    objc_isa = metadata->GetISAPtr();406 407  if (!objc_isa)408    return false;409 410  if (!interface_decl->hasExternalVisibleStorage())411    return true;412 413  interface_decl->startDefinition();414 415  interface_decl->setHasExternalVisibleStorage(false);416  interface_decl->setHasExternalLexicalStorage(false);417 418  ObjCLanguageRuntime::ClassDescriptorSP descriptor =419      m_runtime.GetClassDescriptorFromISA(objc_isa);420 421  if (!descriptor)422    return false;423 424  auto superclass_func = [interface_decl,425                          this](ObjCLanguageRuntime::ObjCISA isa) {426    clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);427 428    if (!superclass_decl)429      return;430 431    FinishDecl(superclass_decl);432    clang::ASTContext &context = m_ast_ctx->getASTContext();433    interface_decl->setSuperClass(context.getTrivialTypeSourceInfo(434        context.getObjCInterfaceType(superclass_decl)));435  };436 437  auto instance_method_func =438      [log, interface_decl, this](const char *name, const char *types) -> bool {439    if (!name || !types)440      return false; // skip this one441 442    ObjCRuntimeMethodType method_type(types);443 444    clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(445        *m_ast_ctx, interface_decl, name, true, m_type_realizer_sp);446 447    LLDB_LOGF(log, "[  AOTV::FD] Instance method [%s] [%s]", name, types);448 449    if (method_decl)450      interface_decl->addDecl(method_decl);451 452    return false;453  };454 455  auto class_method_func = [log, interface_decl,456                            this](const char *name, const char *types) -> bool {457    if (!name || !types)458      return false; // skip this one459 460    ObjCRuntimeMethodType method_type(types);461 462    clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(463        *m_ast_ctx, interface_decl, name, false, m_type_realizer_sp);464 465    LLDB_LOGF(log, "[  AOTV::FD] Class method [%s] [%s]", name, types);466 467    if (method_decl)468      interface_decl->addDecl(method_decl);469 470    return false;471  };472 473  auto ivar_func = [log, interface_decl,474                    this](const char *name, const char *type,475                          lldb::addr_t offset_ptr, uint64_t size) -> bool {476    if (!name || !type)477      return false;478 479    const bool for_expression = false;480 481    LLDB_LOGF(log,482              "[  AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64,483              name, type, offset_ptr);484 485    CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType(486        *m_ast_ctx, type, for_expression);487 488    if (ivar_type.IsValid()) {489      clang::TypeSourceInfo *const type_source_info = nullptr;490      const bool is_synthesized = false;491      clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create(492          m_ast_ctx->getASTContext(), interface_decl, clang::SourceLocation(),493          clang::SourceLocation(), &m_ast_ctx->getASTContext().Idents.get(name),494          ClangUtil::GetQualType(ivar_type),495          type_source_info, // TypeSourceInfo *496          clang::ObjCIvarDecl::Public, nullptr, is_synthesized);497 498      if (ivar_decl) {499        interface_decl->addDecl(ivar_decl);500      }501    }502 503    return false;504  };505 506  LLDB_LOGF(log,507            "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C "508            "interface for %s",509            descriptor->GetClassName().AsCString());510 511  if (!descriptor->Describe(superclass_func, instance_method_func,512                            class_method_func, ivar_func))513    return false;514 515  if (log) {516    LLDB_LOGF(517        log,518        "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface");519 520    LLDB_LOG(log, "  [AOTV::FD] {0}", ClangUtil::DumpDecl(interface_decl));521  }522 523  return true;524}525 526uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append,527                                        uint32_t max_matches,528                                        std::vector<CompilerDecl> &decls) {529 530  Log *log(531      GetLog(LLDBLog::Expressions)); // FIXME - a more appropriate log channel?532 533  LLDB_LOGF(log, "AppleObjCDeclVendor::FindDecls ('%s', %s, %u, )",534            (const char *)name.AsCString(), append ? "true" : "false",535            max_matches);536 537  if (!append)538    decls.clear();539 540  // See if the type is already in our ASTContext.541 542  clang::ASTContext &ast_ctx = m_ast_ctx->getASTContext();543 544  clang::IdentifierInfo &identifier_info =545      ast_ctx.Idents.get(name.GetStringRef());546  clang::DeclarationName decl_name =547      ast_ctx.DeclarationNames.getIdentifier(&identifier_info);548 549  clang::DeclContext::lookup_result lookup_result =550      ast_ctx.getTranslationUnitDecl()->lookup(decl_name);551 552  if (!lookup_result.empty()) {553    if (clang::ObjCInterfaceDecl *result_iface_decl =554            llvm::dyn_cast<clang::ObjCInterfaceDecl>(*lookup_result.begin())) {555      if (log) {556        clang::QualType result_iface_type =557            ast_ctx.getObjCInterfaceType(result_iface_decl);558 559        uint64_t isa_value = LLDB_INVALID_ADDRESS;560        if (std::optional<ClangASTMetadata> metadata =561                m_ast_ctx->GetMetadata(result_iface_decl))562          isa_value = metadata->GetISAPtr();563 564        LLDB_LOGF(log,565                  "AOCTV::FT Found %s (isa 0x%" PRIx64 ") in the ASTContext",566                  result_iface_type.getAsString().data(), isa_value);567      }568 569      decls.push_back(m_ast_ctx->GetCompilerDecl(result_iface_decl));570      return 1;571    }572 573    LLDB_LOGF(log, "AOCTV::FT There's something in the ASTContext, but "574                   "it's not something we know about");575    return 0;576  }577 578  LLDB_LOGF(log, "AOCTV::FT Couldn't find %s in the ASTContext",579            name.AsCString());580 581  // It's not.  If it exists, we have to put it into our ASTContext.582 583  ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);584 585  if (!isa) {586    LLDB_LOGF(log, "AOCTV::FT Couldn't find the isa");587 588    return 0;589  }590 591  clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);592 593  if (!iface_decl) {594    LLDB_LOGF(log,595              "AOCTV::FT Couldn't get the Objective-C interface for "596              "isa 0x%" PRIx64,597              (uint64_t)isa);598 599    return 0;600  }601 602  if (log) {603    clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl);604 605    LLDB_LOG(log, "AOCTV::FT Created {0} (isa 0x{1:x})",606             new_iface_type.getAsString(), (uint64_t)isa);607  }608 609  decls.push_back(m_ast_ctx->GetCompilerDecl(iface_decl));610  return 1;611}612