Home | History | Annotate | Download | only in AppleObjCRuntime
      1 //===-- AppleObjCSymbolVendor.cpp -------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "AppleObjCTypeVendor.h"
     11 
     12 #include "lldb/Core/Log.h"
     13 #include "lldb/Core/Module.h"
     14 #include "lldb/Expression/ASTDumper.h"
     15 #include "lldb/Symbol/ClangExternalASTSourceCommon.h"
     16 #include "lldb/Target/ObjCLanguageRuntime.h"
     17 #include "lldb/Target/Process.h"
     18 #include "lldb/Target/Target.h"
     19 
     20 #include "clang/AST/ASTContext.h"
     21 #include "clang/AST/DeclObjC.h"
     22 
     23 using namespace lldb_private;
     24 
     25 class lldb_private::AppleObjCExternalASTSource : public ClangExternalASTSourceCommon
     26 {
     27 public:
     28     AppleObjCExternalASTSource (AppleObjCTypeVendor &type_vendor) :
     29         m_type_vendor(type_vendor)
     30     {
     31     }
     32 
     33     bool
     34     FindExternalVisibleDeclsByName (const clang::DeclContext *decl_ctx,
     35                                     clang::DeclarationName name)
     36     {
     37         static unsigned int invocation_id = 0;
     38         unsigned int current_id = invocation_id++;
     39 
     40         Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
     41 
     42         if (log)
     43         {
     44             log->Printf("AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
     45                         current_id,
     46                         &decl_ctx->getParentASTContext(),
     47                         name.getAsString().c_str(),
     48                         decl_ctx->getDeclKindName(),
     49                         decl_ctx);
     50         }
     51 
     52         do
     53         {
     54             const clang::ObjCInterfaceDecl *interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
     55 
     56             if (!interface_decl)
     57                 break;
     58 
     59             clang::ObjCInterfaceDecl *non_const_interface_decl = const_cast<clang::ObjCInterfaceDecl*>(interface_decl);
     60 
     61             if (!m_type_vendor.FinishDecl(non_const_interface_decl))
     62                 break;
     63 
     64             clang::DeclContext::lookup_const_result result = non_const_interface_decl->lookup(name);
     65 
     66             return (result.size() != 0);
     67         }
     68         while(0);
     69 
     70         SetNoExternalVisibleDeclsForName(decl_ctx, name);
     71         return false;
     72     }
     73 
     74     clang::ExternalLoadResult
     75     FindExternalLexicalDecls (const clang::DeclContext *DC,
     76                               bool (*isKindWeWant)(clang::Decl::Kind),
     77                               llvm::SmallVectorImpl<clang::Decl*> &Decls)
     78     {
     79         return clang::ELR_Success;
     80     }
     81 
     82     void
     83     CompleteType (clang::TagDecl *tag_decl)
     84     {
     85         static unsigned int invocation_id = 0;
     86         unsigned int current_id = invocation_id++;
     87 
     88         Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
     89 
     90         if (log)
     91         {
     92             log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s",
     93                         current_id,
     94                         &tag_decl->getASTContext(),
     95                         tag_decl,
     96                         tag_decl->getName().str().c_str());
     97 
     98             log->Printf("  AOEAS::CT[%u] Before:", current_id);
     99             ASTDumper dumper((clang::Decl*)tag_decl);
    100             dumper.ToLog(log, "    [CT] ");
    101         }
    102 
    103         if (log)
    104         {
    105             log->Printf("  AOEAS::CT[%u] After:", current_id);
    106             ASTDumper dumper((clang::Decl*)tag_decl);
    107             dumper.ToLog(log, "    [CT] ");
    108         }
    109         return;
    110     }
    111 
    112     void
    113     CompleteType (clang::ObjCInterfaceDecl *interface_decl)
    114     {
    115         static unsigned int invocation_id = 0;
    116         unsigned int current_id = invocation_id++;
    117 
    118         Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
    119 
    120         if (log)
    121         {
    122             log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
    123                         current_id,
    124                         &interface_decl->getASTContext(),
    125                         interface_decl,
    126                         interface_decl->getName().str().c_str());
    127 
    128             log->Printf("  AOEAS::CT[%u] Before:", current_id);
    129             ASTDumper dumper((clang::Decl*)interface_decl);
    130             dumper.ToLog(log, "    [CT] ");
    131         }
    132 
    133         m_type_vendor.FinishDecl(interface_decl);
    134 
    135         if (log)
    136         {
    137             log->Printf("  [CT] After:");
    138             ASTDumper dumper((clang::Decl*)interface_decl);
    139             dumper.ToLog(log, "    [CT] ");
    140         }
    141         return;
    142     }
    143 
    144     bool
    145     layoutRecordType(const clang::RecordDecl *Record,
    146                      uint64_t &Size,
    147                      uint64_t &Alignment,
    148                      llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
    149                      llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
    150                      llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
    151     {
    152         return false;
    153     }
    154 
    155     void StartTranslationUnit (clang::ASTConsumer *Consumer)
    156     {
    157         clang::TranslationUnitDecl *translation_unit_decl = m_type_vendor.m_ast_ctx.getASTContext()->getTranslationUnitDecl();
    158         translation_unit_decl->setHasExternalVisibleStorage();
    159         translation_unit_decl->setHasExternalLexicalStorage();
    160     }
    161 private:
    162     AppleObjCTypeVendor                                    &m_type_vendor;
    163 };
    164 
    165 AppleObjCTypeVendor::AppleObjCTypeVendor(ObjCLanguageRuntime &runtime) :
    166     TypeVendor(),
    167     m_runtime(runtime),
    168     m_ast_ctx(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().getTriple().c_str())
    169 {
    170     m_external_source = new AppleObjCExternalASTSource (*this);
    171     llvm::OwningPtr<clang::ExternalASTSource> external_source_owning_ptr (m_external_source);
    172     m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr);
    173 }
    174 
    175 clang::ObjCInterfaceDecl*
    176 AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
    177 {
    178     ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
    179 
    180     if (iter != m_isa_to_interface.end())
    181         return iter->second;
    182 
    183     clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
    184 
    185     ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(isa);
    186 
    187     if (!descriptor)
    188         return NULL;
    189 
    190     const ConstString &name(descriptor->GetClassName());
    191 
    192     clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
    193 
    194     clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx,
    195                                                                                 ast_ctx->getTranslationUnitDecl(),
    196                                                                                 clang::SourceLocation(),
    197                                                                                 &identifier_info,
    198                                                                                 NULL);
    199 
    200     ClangASTMetadata meta_data;
    201     meta_data.SetISAPtr(isa);
    202     m_external_source->SetMetadata(new_iface_decl, meta_data);
    203 
    204     new_iface_decl->setHasExternalVisibleStorage();
    205     new_iface_decl->setHasExternalLexicalStorage();
    206 
    207     ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
    208 
    209     m_isa_to_interface[isa] = new_iface_decl;
    210 
    211     return new_iface_decl;
    212 }
    213 
    214 class ObjCRuntimeMethodType
    215 {
    216 public:
    217     ObjCRuntimeMethodType (const char *types) : m_is_valid(false)
    218     {
    219         const char *cursor = types;
    220         enum ParserState {
    221             Start = 0,
    222             InType,
    223             InPos
    224         } state = Start;
    225         const char *type = NULL;
    226         int brace_depth = 0;
    227 
    228         uint32_t stepsLeft = 256;
    229 
    230         while (1)
    231         {
    232             if (--stepsLeft == 0)
    233             {
    234                 m_is_valid = false;
    235                 return;
    236             }
    237 
    238             switch (state)
    239             {
    240             case Start:
    241                 {
    242                     switch (*cursor)
    243                     {
    244                     default:
    245                         state = InType;
    246                         type = cursor;
    247                         break;
    248                     case '\0':
    249                         m_is_valid = true;
    250                         return;
    251                     case '0': case '1': case '2': case '3': case '4':
    252                     case '5': case '6': case '7': case '8': case '9':
    253                         m_is_valid = false;
    254                         return;
    255                     }
    256                 }
    257                 break;
    258             case InType:
    259                 {
    260                     switch (*cursor)
    261                     {
    262                     default:
    263                         ++cursor;
    264                         break;
    265                     case '0': case '1': case '2': case '3': case '4':
    266                     case '5': case '6': case '7': case '8': case '9':
    267                         if (!brace_depth)
    268                         {
    269                             state = InPos;
    270                             if (type)
    271                             {
    272                                 m_type_vector.push_back(std::string(type, (cursor - type)));
    273                             }
    274                             else
    275                             {
    276                                 m_is_valid = false;
    277                                 return;
    278                             }
    279                             type = NULL;
    280                         }
    281                         else
    282                         {
    283                             ++cursor;
    284                         }
    285                         break;
    286                     case '[': case '{': case '(':
    287                         ++brace_depth;
    288                         ++cursor;
    289                         break;
    290                     case ']': case '}': case ')':
    291                         if (!brace_depth)
    292                         {
    293                             m_is_valid = false;
    294                             return;
    295                         }
    296                         --brace_depth;
    297                         ++cursor;
    298                         break;
    299                     case '\0':
    300                         m_is_valid = false;
    301                         return;
    302                     }
    303                 }
    304                 break;
    305             case InPos:
    306                 {
    307                     switch (*cursor)
    308                     {
    309                     default:
    310                         state = InType;
    311                         type = cursor;
    312                         break;
    313                     case '0': case '1': case '2': case '3': case '4':
    314                     case '5': case '6': case '7': case '8': case '9':
    315                         ++cursor;
    316                         break;
    317                     case '\0':
    318                         m_is_valid = true;
    319                         return;
    320                     }
    321                 }
    322                 break;
    323             }
    324         }
    325     }
    326 
    327     clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance)
    328     {
    329         if (!m_is_valid || m_type_vector.size() < 3)
    330             return NULL;
    331 
    332         clang::ASTContext &ast_ctx(interface_decl->getASTContext());
    333 
    334         clang::QualType return_qual_type;
    335 
    336         const bool isInstance = instance;
    337         const bool isVariadic = false;
    338         const bool isSynthesized = false;
    339         const bool isImplicitlyDeclared = true;
    340         const bool isDefined = false;
    341         const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None;
    342         const bool HasRelatedResultType = false;
    343 
    344         std::vector <clang::IdentifierInfo *> selector_components;
    345 
    346         const char *name_cursor = name;
    347         bool is_zero_argument = true;
    348 
    349         while (*name_cursor != '\0')
    350         {
    351             const char *colon_loc = strchr(name_cursor, ':');
    352             if (!colon_loc)
    353             {
    354                 selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
    355                 break;
    356             }
    357             else
    358             {
    359                 is_zero_argument = false;
    360                 selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor, colon_loc - name_cursor)));
    361                 name_cursor = colon_loc + 1;
    362             }
    363         }
    364 
    365         clang::Selector sel = ast_ctx.Selectors.getSelector(is_zero_argument ? 0 : selector_components.size(), selector_components.data());
    366 
    367         clang::QualType ret_type = BuildType(ast_ctx, m_type_vector[0].c_str());
    368 
    369         if (ret_type.isNull())
    370             return NULL;
    371 
    372         clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(ast_ctx,
    373                                                                    clang::SourceLocation(),
    374                                                                    clang::SourceLocation(),
    375                                                                    sel,
    376                                                                    ret_type,
    377                                                                    NULL,
    378                                                                    interface_decl,
    379                                                                    isInstance,
    380                                                                    isVariadic,
    381                                                                    isSynthesized,
    382                                                                    isImplicitlyDeclared,
    383                                                                    isDefined,
    384                                                                    impControl,
    385                                                                    HasRelatedResultType);
    386 
    387         std::vector <clang::ParmVarDecl*> parm_vars;
    388 
    389         for (size_t ai = 3, ae = m_type_vector.size();
    390              ai != ae;
    391              ++ai)
    392         {
    393             clang::QualType arg_type = BuildType(ast_ctx, m_type_vector[ai].c_str());
    394 
    395             if (arg_type.isNull())
    396                 return NULL; // well, we just wasted a bunch of time.  Wish we could delete the stuff we'd just made!
    397 
    398             parm_vars.push_back(clang::ParmVarDecl::Create(ast_ctx,
    399                                                            ret,
    400                                                            clang::SourceLocation(),
    401                                                            clang::SourceLocation(),
    402                                                            NULL,
    403                                                            arg_type,
    404                                                            NULL,
    405                                                            clang::SC_None,
    406                                                            NULL));
    407         }
    408 
    409         ret->setMethodParams(ast_ctx, llvm::ArrayRef<clang::ParmVarDecl*>(parm_vars), llvm::ArrayRef<clang::SourceLocation>());
    410 
    411         return ret;
    412     }
    413 private:
    414     clang::QualType BuildType (clang::ASTContext &ast_ctx, const char *type)
    415     {
    416         if (!type)
    417             return clang::QualType();
    418 
    419         switch (*type)
    420         {
    421         default:
    422             return ast_ctx.UnknownAnyTy;
    423         case 'r':
    424             {
    425                 clang::QualType target_type = BuildType(ast_ctx, type+1);
    426                 if (target_type.isNull())
    427                     return clang::QualType();
    428                 else if (target_type == ast_ctx.UnknownAnyTy)
    429                     return ast_ctx.UnknownAnyTy;
    430                 else
    431                     return ast_ctx.getConstType(target_type);
    432             }
    433         case '^':
    434         {
    435             clang::QualType target_type = BuildType(ast_ctx, type+1);
    436             if (target_type.isNull())
    437                 return clang::QualType();
    438             else if (target_type == ast_ctx.UnknownAnyTy)
    439                 return ast_ctx.UnknownAnyTy;
    440             else
    441                 return ast_ctx.getPointerType(target_type);
    442         }
    443         case 'c':
    444             return ast_ctx.CharTy;
    445         case 'i':
    446             return ast_ctx.IntTy;
    447         case 's':
    448             return ast_ctx.ShortTy;
    449         case 'l':
    450             if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
    451                 return ast_ctx.IntTy;
    452             else
    453                 return ast_ctx.LongTy;
    454         case 'q':
    455             return ast_ctx.LongLongTy;
    456         case 'C':
    457             return ast_ctx.UnsignedCharTy;
    458         case 'I':
    459             return ast_ctx.UnsignedIntTy;
    460         case 'S':
    461             return ast_ctx.UnsignedShortTy;
    462         case 'L':
    463             if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
    464                 return ast_ctx.UnsignedIntTy;
    465             else
    466                 return ast_ctx.UnsignedLongTy;
    467         case 'Q':
    468             return ast_ctx.UnsignedLongLongTy;
    469         case 'f':
    470             return ast_ctx.FloatTy;
    471         case 'd':
    472             return ast_ctx.DoubleTy;
    473         case 'B':
    474             return ast_ctx.BoolTy;
    475         case 'v':
    476             return ast_ctx.VoidTy;
    477         case '*':
    478             return ast_ctx.getPointerType(ast_ctx.CharTy);
    479         case '@':
    480             return ast_ctx.getObjCIdType();
    481         case '#':
    482             return ast_ctx.getObjCClassType();
    483         case ':':
    484             return ast_ctx.getObjCSelType();
    485         }
    486         return clang::QualType();
    487     }
    488 
    489     typedef std::vector <std::string> TypeVector;
    490 
    491     TypeVector  m_type_vector;
    492     bool        m_is_valid;
    493 };
    494 
    495 bool
    496 AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
    497 {
    498     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
    499 
    500     ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl);
    501     ObjCLanguageRuntime::ObjCISA objc_isa = 0;
    502     if (metadata)
    503      objc_isa = metadata->GetISAPtr();
    504 
    505     if (!objc_isa)
    506         return false;
    507 
    508     if (!interface_decl->hasExternalVisibleStorage())
    509         return true;
    510 
    511     interface_decl->startDefinition();
    512 
    513     interface_decl->setHasExternalVisibleStorage(false);
    514     interface_decl->setHasExternalLexicalStorage(false);
    515 
    516     ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(objc_isa);
    517 
    518     if (!descriptor)
    519         return false;
    520 
    521     auto superclass_func = [interface_decl, this](ObjCLanguageRuntime::ObjCISA isa)
    522     {
    523         clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
    524         if (!superclass_decl)
    525             return;
    526         interface_decl->setSuperClass(superclass_decl);
    527     };
    528 
    529     auto instance_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool
    530     {
    531         ObjCRuntimeMethodType method_type(types);
    532 
    533         clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, true);
    534 
    535         if (log)
    536             log->Printf("[  AOTV::FD] Instance method [%s] [%s]", name, types);
    537 
    538         if (method_decl)
    539             interface_decl->addDecl(method_decl);
    540 
    541         return false;
    542     };
    543 
    544     auto class_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool
    545     {
    546         ObjCRuntimeMethodType method_type(types);
    547 
    548         clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, false);
    549 
    550         if (log)
    551             log->Printf("[  AOTV::FD] Class method [%s] [%s]", name, types);
    552 
    553         if (method_decl)
    554             interface_decl->addDecl(method_decl);
    555 
    556         return false;
    557     };
    558 
    559     if (log)
    560     {
    561         ASTDumper method_dumper ((clang::Decl*)interface_decl);
    562 
    563         log->Printf("[AppleObjCTypeVendor::FinishDecl] Finishing Objective-C interface for %s", descriptor->GetClassName().AsCString());
    564     }
    565 
    566 
    567     if (!descriptor->Describe(superclass_func,
    568                               instance_method_func,
    569                               class_method_func,
    570                               std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr)))
    571         return false;
    572 
    573     if (log)
    574     {
    575         ASTDumper method_dumper ((clang::Decl*)interface_decl);
    576 
    577         log->Printf("[AppleObjCTypeVendor::FinishDecl] Finished Objective-C interface");
    578 
    579         method_dumper.ToLog(log, "  [AOTV::FD] ");
    580     }
    581 
    582     return true;
    583 }
    584 
    585 uint32_t
    586 AppleObjCTypeVendor::FindTypes (const ConstString &name,
    587                                 bool append,
    588                                 uint32_t max_matches,
    589                                 std::vector <ClangASTType> &types)
    590 {
    591     static unsigned int invocation_id = 0;
    592     unsigned int current_id = invocation_id++;
    593 
    594     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
    595 
    596     if (log)
    597         log->Printf("AppleObjCTypeVendor::FindTypes [%u] ('%s', %s, %u, )",
    598                     current_id,
    599                     (const char*)name.AsCString(),
    600                     append ? "true" : "false",
    601                     max_matches);
    602 
    603     if (!append)
    604         types.clear();
    605 
    606     uint32_t ret = 0;
    607 
    608     do
    609     {
    610         // See if the type is already in our ASTContext.
    611 
    612         clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
    613 
    614         clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
    615         clang::DeclarationName decl_name = ast_ctx->DeclarationNames.getIdentifier(&identifier_info);
    616 
    617         clang::DeclContext::lookup_const_result lookup_result = ast_ctx->getTranslationUnitDecl()->lookup(decl_name);
    618 
    619         if (!lookup_result.empty())
    620         {
    621             if (const clang::ObjCInterfaceDecl *result_iface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0]))
    622             {
    623                 clang::QualType result_iface_type = ast_ctx->getObjCInterfaceType(result_iface_decl);
    624 
    625                 if (log)
    626                 {
    627                     ASTDumper dumper(result_iface_type);
    628 
    629                     uint64_t isa_value = LLDB_INVALID_ADDRESS;
    630                     ClangASTMetadata *metadata = m_external_source->GetMetadata(result_iface_decl);
    631                     if (metadata)
    632                         isa_value = metadata->GetISAPtr();
    633 
    634                     log->Printf("AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 ") in the ASTContext",
    635                                 current_id,
    636                                 dumper.GetCString(),
    637                                 isa_value);
    638                 }
    639 
    640                 types.push_back(ClangASTType(ast_ctx, result_iface_type.getAsOpaquePtr()));
    641                 ret++;
    642                 break;
    643             }
    644             else
    645             {
    646                 if (log)
    647                     log->Printf("AOCTV::FT [%u] There's something in the ASTContext, but it's not something we know about",
    648                                 current_id);
    649                 break;
    650             }
    651         }
    652         else if(log)
    653         {
    654             log->Printf("AOCTV::FT [%u] Couldn't find %s in the ASTContext",
    655                         current_id,
    656                         name.AsCString());
    657         }
    658 
    659         // It's not.  If it exists, we have to put it into our ASTContext.
    660 
    661         ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
    662 
    663         if (!isa)
    664         {
    665             if (log)
    666                 log->Printf("AOCTV::FT [%u] Couldn't find the isa",
    667                             current_id);
    668 
    669             break;
    670         }
    671 
    672         clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
    673 
    674         if (!iface_decl)
    675         {
    676             if (log)
    677                 log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for isa 0x%" PRIx64,
    678                             current_id,
    679                             (uint64_t)isa);
    680 
    681             break;
    682         }
    683 
    684         clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(iface_decl);
    685 
    686         if (log)
    687         {
    688             ASTDumper dumper(new_iface_type);
    689             log->Printf("AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")",
    690                         current_id,
    691                         dumper.GetCString(),
    692                         (uint64_t)isa);
    693         }
    694 
    695         types.push_back(ClangASTType(ast_ctx, new_iface_type.getAsOpaquePtr()));
    696         ret++;
    697         break;
    698     } while (0);
    699 
    700     return ret;
    701 }
    702