682 lines
24 KiB
C++
682 lines
24 KiB
C++
//===-- 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 "Plugins/ExpressionParser/Clang/ASTDumper.h"
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
|
|
#include "lldb/Symbol/ClangUtil.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 = ClangUtil::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 = ClangUtil::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;
|
|
}
|
|
|
|
explicit operator bool ()
|
|
{
|
|
return m_is_valid;
|
|
}
|
|
|
|
size_t
|
|
GetNumTypes ()
|
|
{
|
|
return m_type_vector.size();
|
|
}
|
|
|
|
const char*
|
|
GetTypeAtIndex (size_t idx)
|
|
{
|
|
return m_type_vector[idx].c_str();
|
|
}
|
|
|
|
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), ClangUtil::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;
|
|
}
|